[NTOS]: Implement all V8086 Opcode emulation in C instead of ASM.
authorSir Richard <sir_richard@svn.reactos.org>
Sun, 10 Jan 2010 15:40:00 +0000 (15:40 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Sun, 10 Jan 2010 15:40:00 +0000 (15:40 +0000)
svn path=/trunk/; revision=45029

reactos/ntoskrnl/include/internal/i386/ke.h
reactos/ntoskrnl/ke/i386/trap.s
reactos/ntoskrnl/ke/i386/v86m_sup.S
reactos/ntoskrnl/ke/i386/v86vdm.c

index d2cb142..52c04c4 100644 (file)
@@ -84,6 +84,60 @@ typedef union _KTRAP_EXIT_SKIP_BITS
     };
     UCHAR Bits;
 } KTRAP_EXIT_SKIP_BITS, *PKTRAP_EXIT_SKIP_BITS;
+
+
+//
+// Flags used by the VDM/V8086 emulation engine for determining instruction prefixes
+//
+#define PFX_FLAG_ES                0x00000100
+#define PFX_FLAG_CS                0x00000200
+#define PFX_FLAG_SS                0x00000400
+#define PFX_FLAG_DS                0x00000800
+#define PFX_FLAG_FS                0x00001000
+#define PFX_FLAG_GS                0x00002000
+#define PFX_FLAG_OPER32            0x00004000
+#define PFX_FLAG_ADDR32            0x00008000
+#define PFX_FLAG_LOCK              0x00010000
+#define PFX_FLAG_REPNE             0x00020000
+#define PFX_FLAG_REP               0x00040000
+
+//
+// VDM Helper Macros
+//
+// All VDM/V8086 opcode emulators have the same FASTCALL function definition.
+// We need to keep 2 parameters while the original ASM implementation uses 4:
+// TrapFrame, PrefixFlags, Eip, InstructionSize;
+//
+// We pass the trap frame, and prefix flags, in our two parameters.
+//
+// We then realize that since the smallest prefix flag is 0x100, this gives us
+// a count of up to 0xFF. So we OR in the instruction size with the prefix flags
+//
+// We further realize that we always have access to EIP from the trap frame, and
+// that if we want the *current instruction* EIP, we simply have to add the
+// instruction size *MINUS ONE*, and that gives us the EIP we should be looking
+// at now, so we don't need to use the stack to push this parameter.
+//
+// We actually only care about the *current instruction* EIP in one location,
+// so although it may be slightly more expensive to re-calculate the EIP one
+// more time, this way we don't redefine ALL opcode handlers to have 3 parameters,
+// which would be forcing stack usage in all other scenarios.
+//
+#define KiVdmSetVdmEFlags(x)        InterlockedOr((PLONG)KiNtVdmState, (x));
+#define KiVdmClearVdmEFlags(x)      InterlockedAnd((PLONG)KiNtVdmState, ~(x))
+#define KiCallVdmHandler(x)         KiVdmOpcode##x(TrapFrame, Flags)
+#define KiCallVdmPrefixHandler(x)   KiVdmOpcodePrefix(TrapFrame, Flags | x)
+#define KiVdmUnhandledOpcode(x)                     \
+    BOOLEAN                                         \
+    FASTCALL                                        \
+    KiVdmOpcode##x(IN PKTRAP_FRAME TrapFrame,       \
+                   IN ULONG Flags)                  \
+    {                                               \
+        /* Not yet handled */                       \
+        UNIMPLEMENTED;                              \
+        while (TRUE);                               \
+    }
+
               
 //
 // Registers an interrupt handler with an IDT vector
index 477bb2c..5a5937b 100644 (file)
@@ -755,7 +755,8 @@ RaiseIrql:
     sti
 
     /* Handle the opcode */
-    call _Ki386HandleOpcodeV86@0
+    mov ecx, ebp
+    call @Ki386HandleOpcodeV86@4
 
     /* Check if this was VDM */
     test al, 0xFF
index 8c17224..1744023 100644 (file)
 #include <internal/i386/asmmacro.S>
 .intel_syntax noprefix
 
-/* FIXME: Can we make a nice macro to generate V86 Opcode handlers? */
-
-/* GLOBALS *******************************************************************/
-
-//
-// This table contains indexes into the OpcodeDispatchV86 Table for opcodes in
-// Virtual-8086 Mode.
-// There are 256 entries.
-//
-OpcodeIndex:
-    INVALID_V86_OPCODE 15                       /* OP 00-14: UNHANDLED       */
-    .byte 1                                     /* OP    0F: 0F              */
-    INVALID_V86_OPCODE 22                       /* OP 10-25: UNHANDLED       */
-    .byte 2                                     /* OP    26: ES Prefix       */
-    INVALID_V86_OPCODE 7                        /* OP 27-2D: UNHANDLED       */
-    .byte 3                                     /* OP    2E: CS Prefix       */
-    INVALID_V86_OPCODE 7                        /* OP 2F-35: UNHANDLED       */
-    .byte 4                                     /* OP    36: SS Prefix       */
-    INVALID_V86_OPCODE 7                        /* OP 37-3D: UNHANDLED       */
-    .byte 5                                     /* OP    3E: DS Prefix       */
-    INVALID_V86_OPCODE 37                       /* OP 3F-63: UNHANDLED       */
-    .byte 6                                     /* OP    64: FS Prefix       */
-    .byte 7                                     /* OP    65: GS Prefix       */
-    .byte 8                                     /* OP    66: OPER32 Prefix   */
-    .byte 9                                     /* OP    67: ADDR32 Prefix   */
-    INVALID_V86_OPCODE 4                        /* OP 68-6B: UNHANDLED       */
-    .byte 10                                    /* OP    6C: INSB            */
-    .byte 11                                    /* OP    6D: INSW            */
-    .byte 12                                    /* OP    6E: OUTSB           */
-    .byte 13                                    /* OP    6F: OUTSW           */
-    INVALID_V86_OPCODE 43                       /* OP 70-9A: UNHANDLED       */
-    .byte 19                                    /* OP    9B: NPX             */
-    .byte 14                                    /* OP    9C: PUSHF           */
-    .byte 15                                    /* OP    9D: POPF            */
-    INVALID_V86_OPCODE 47                       /* OP 9E-CC: UNHANDLED       */
-    .byte 16                                    /* OP    CD: INTnn           */
-    .byte 17                                    /* OP    CE: INTO            */
-    .byte 18                                    /* OP    CF: IRETD           */
-    INVALID_V86_OPCODE 8                        /* OP D0-D7: UNHANDLED       */
-    .byte 19                                    /* OP    D8: NPX             */
-    .byte 19                                    /* OP    D9: NPX             */
-    .byte 19                                    /* OP    DA: NPX             */
-    .byte 19                                    /* OP    DB: NPX             */
-    .byte 19                                    /* OP    DC: NPX             */
-    .byte 19                                    /* OP    DD: NPX             */
-    .byte 19                                    /* OP    DE: NPX             */
-    .byte 19                                    /* OP    DF: NPX             */
-    INVALID_V86_OPCODE 4                        /* OP DE-E3: UNHANDLED       */
-    .byte 20                                    /* OP    E4: INBimm          */
-    .byte 21                                    /* OP    E5: INWimm          */
-    .byte 22                                    /* OP    E6: OUTBimm         */
-    .byte 23                                    /* OP    E7: OUTWimm         */
-    INVALID_V86_OPCODE 4                        /* OP E8-EB: UNHANDLED       */
-    .byte 24                                    /* OP    EC: INB             */
-    .byte 25                                    /* OP    EF: INW             */
-    .byte 26                                    /* OP    EE: OUTB            */
-    .byte 27                                    /* OP    EF: OUTW            */
-    .byte 28                                    /* OP    F0: LOCK Prefix     */
-    .byte 0                                     /* OP    F1: UNHANDLED       */
-    .byte 29                                    /* OP    F2: REPNE Prefix    */
-    .byte 30                                    /* OP    F3: REP Prefix      */
-    .byte 33                                    /* OP    F4: HLT             */
-    INVALID_V86_OPCODE 5                        /* OP F5-F9: UNHANDLED       */
-    .byte 31                                    /* OP    FA: CLI             */
-    .byte 32                                    /* OP    FB: STI             */
-    INVALID_V86_OPCODE 4                        /* OP FC-FF: UNHANDLED       */
-
-//
-// This table contains the emulation routines for
-// Virtual-8086 Mode. There are 34 entries.
-//
-OpcodeDispatchV86:
-    .long _OpcodeInvalidV86
-    .long _Opcode0FV86
-    .long _OpcodeESPrefixV86
-    .long _OpcodeCSPrefixV86
-    .long _OpcodeSSPrefixV86
-    .long _OpcodeDSPrefixV86
-    .long _OpcodeFSPrefixV86
-    .long _OpcodeGSPrefixV86
-    .long _OpcodeOPER32PrefixV86
-    .long _OpcodeADDR32PrefixV86
-    .long _OpcodeINSBV86
-    .long _OpcodeINSWV86
-    .long _OpcodeOUTSBV86
-    .long _OpcodeOUTSWV86
-    .long _OpcodePUSHFV86
-    .long _OpcodePOPFV86
-    .long _OpcodeINTnnV86
-    .long _OpcodeINTOV86
-    .long _OpcodeIRETV86
-    .long _OpcodeNPXV86
-    .long _OpcodeINBimmV86
-    .long _OpcodeINWimmV86
-    .long _OpcodeOUTBimmV86
-    .long _OpcodeOUTWimmV86
-    .long _OpcodeINBV86
-    .long _OpcodeINWV86
-    .long _OpcodeOUTBV86
-    .long _OpcodeOUTWV86
-    .long _OpcodeLOCKPrefixV86
-    .long _OpcodeREPNEPrefixV86
-    .long _OpcodeREPPrefixV86
-    .long _OpcodeCLIV86
-    .long _OpcodeSTIV86
-    .long _OpcodeHLTV86
-
-_ExVdmOpcodeDispatchCounts:
-    .rept 34
-        .long 0
-    .endr
-
-V86DebugMsg:
-    .asciz "Received V86 Emulation Opcode: %lx\n"
-
-/* VIRTUAL-8086 MODE OPCODER HANDLERS ****************************************/
-
-.func OpcodeInvalidV86
-_OpcodeInvalidV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func Opcode0FV86
-_Opcode0FV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-#undef LOCK
-
-GENERATE_PREFIX_HANDLER ES
-GENERATE_PREFIX_HANDLER CS
-GENERATE_PREFIX_HANDLER DS
-GENERATE_PREFIX_HANDLER FS
-GENERATE_PREFIX_HANDLER GS
-GENERATE_PREFIX_HANDLER SS
-GENERATE_PREFIX_HANDLER OPER32
-GENERATE_PREFIX_HANDLER ADDR32
-GENERATE_PREFIX_HANDLER LOCK
-GENERATE_PREFIX_HANDLER REP
-GENERATE_PREFIX_HANDLER REPNE
-
-#ifdef CONFIG_SMP
-#define LOCK lock
-#else
-#define LOCK
-#endif
-
-.func OpcodeINSBV86
-_OpcodeINSBV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeINSWV86
-_OpcodeINSWV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeOUTSBV86
-_OpcodeOUTSBV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeOUTSWV86
-_OpcodeOUTSWV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodePUSHFV86
-_OpcodePUSHFV86:
-
-    /* Get VDM state */
-    mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
-    mov eax, [eax]
-
-    /* Get EFLAGS and mask out IF */
-    mov edx, [ebp+KTRAP_FRAME_EFLAGS]
-    and eax, ~EFLAGS_INTERRUPT_MASK
-
-    /* Mask align check and interrupt mask */
-    and eax, EFLAGS_ALIGN_CHECK + EFLAGS_NESTED_TASK + EFLAGS_INTERRUPT_MASK
-    or eax, edx
-
-    /* Add IOPL Mask */
-    or eax, EFLAGS_IOPL
-
-    /* Get flat ESP */
-    movzx ecx, word ptr [ebp+KTRAP_FRAME_SS]
-    shl ecx, 4
-    movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
-    sub dx, 2
-
-    /* Check if there is an OPER32 prefix */
-    test ebx, PREFIX_FLAG_OPER32
-    jnz SkipPrefix
-
-    /* Push EFLAGS */
-    mov [ecx+edx], ax
-
-UpdateFrame:
-
-    /* Update ESP and EIP */
-    mov [ebp+KTRAP_FRAME_ESP], dx
-    add [ebp+KTRAP_FRAME_EIP], edi
-
-    /* Return success */
-    mov eax, 1
-    ret
-
-SkipPrefix:
-
-    /* Skip the prefix, push EFLAGS and jump back */
-    sub dx, 2
-    mov [edx+ecx], eax
-    jmp UpdateFrame
-.endfunc
-
-.func OpcodePOPFV86
-_OpcodePOPFV86:
-
-    /* Get VDM state */
-    mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
-
-    /* Get flat ESP */
-    mov ecx, [ebp+KTRAP_FRAME_SS]
-    shl ecx, 4
-    movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
-
-    /* Pop EFLAGS */
-    mov ecx, [ecx+edx]
-    add edx, 4
-
-    /* Check for OPER32 prefix */
-    test ebx, PREFIX_FLAG_OPER32
-    jnz NoPrefix
-
-    /* Skip 2 bytes */
-    and ecx, 0xFFFF
-    sub edx, 2
-
-NoPrefix:
-
-    /* Set new ESP */
-    mov [ebp+KTRAP_FRAME_ESP], edx
-
-    /* Mask out EFLAGS */
-    and eax, ~EFLAGS_IOPL
-    mov ebx, ebx
-    and ebx, ~EFLAGS_NESTED_TASK
-    and ecx, EFLAGS_ALIGN_CHECK + EFLAGS_NESTED_TASK + EFLAGS_INTERRUPT_MASK
-
-    /* FIXME: Support VME */
-
-    /* Save VDM State pointer */
-    push eax
-
-    /* Set new EFLAGS, make sure to add IF and V86 */
-    or ebx, EFLAGS_INTERRUPT_MASK + EFLAGS_V86_MASK
-    push [ebp+KTRAP_FRAME_EFLAGS]
-    mov [ebp+KTRAP_FRAME_EFLAGS], ebx
-
-    /* Make sure we were in V86 mode */
-    test ebx, EFLAGS_V86_MASK
-    jnz CheckEspAdjust
-    int 3
-
-CheckEspAdjust:
-
-    /* Check if we have to update ESP0 and fixup the stack from our push */
-    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
-    lea esp, [esp+4]
-    jnz NoAdjustEsp0
-
-    /* Adjust it */
-    push ebp
-    call _Ki386AdjustEsp0@4
-
-NoAdjustEsp0:
-
-    /* Restore VDM state */
-    pop eax
-
-    /* Update the flags in the VDM State */
-    LOCK and dword ptr [eax], ~(EFLAGS_ALIGN_CHECK + EFLAGS_NESTED_TASK + EFLAGS_INTERRUPT_MASK)
-    LOCK or [eax], ecx
-
-    /* Update EIP */
-    add [ebp+KTRAP_FRAME_EIP], edi
-
-    /* FIXME: Check for VDM Pending interrupts */
-
-    /* Return success */
-    mov eax, 1
-    ret
-.endfunc
-
-.func OpcodeINTnnV86
-_OpcodeINTnnV86:
-
-    /* Get EFlags */
-    mov edx, [ebp+KTRAP_FRAME_EFLAGS]
-
-    /* Remove the flag in the VDM State */
-    mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
-    mov ecx, [eax]
-    LOCK and dword ptr [eax], ~EFLAGS_INTERRUPT_MASK
-
-    /* Mask it out from EFLAGS too */
-    mov eax, edx
-    and eax, ~EFLAGS_INTERRUPT_MASK
-
-    /* Mask out the alignment check and IF flag from the VDM state */
-    and ecx, EFLAGS_ALIGN_CHECK + EFLAGS_INTERRUPT_MASK
-
-    /* FIXME: Support VME */
-
-    /* Now mask out VIF and TF */
-    or eax, ecx
-    and edx, ~(EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_TF)
-    mov [ebp+KTRAP_FRAME_EFLAGS], edx
-
-    /* Set the IOPL Mask */
-    or eax, EFLAGS_IOPL
-
-    /* Get stack flat address */
-    movzx ecx, word ptr [ebp+KTRAP_FRAME_SS]
-    shl ecx, 4
-    movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
-
-    /* Push EFLAGS */
-    sub dx, 2
-    mov word ptr [ecx+edx], ax
-
-    /* Push CS */
-    mov ax, word ptr [ebp+KTRAP_FRAME_CS]
-    sub dx, 2
-    mov word ptr [ecx+edx], ax
-
-    /* Push IP */
-    movzx eax, word ptr [ebp+KTRAP_FRAME_EIP]
-    add eax, edi
-    inc eax
-    sub dx, 2
-    mov word ptr [ecx+edx], ax
-
-    /* Update ESP */
-    mov [ebp+KTRAP_FRAME_ESP], dx
-
-    /* Get the interrupt */
-    inc esi
-    movzx ecx, byte ptr [esi]
-    /* FIXME: Analyze and see if this is a hooked VDM (PM) Interrupt */
-
-    /* Get the entry in the IVT */
-    mov ebx, [ecx*4]
-    mov eax, ebx
-    shr eax, 16
-
-    /* Update EIP */
-    mov word ptr [ebp+KTRAP_FRAME_EIP], bx
-
-    /* Check if this was V86 mode */
-    test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
-    jnz SetCs
-
-    /* Check if it was a kernel CS */
-    or ax, RPL_MASK
-    cmp ax, KGDT_R0_CODE
-    jnb SetCs
-
-    /* Set user-mode CS */
-    mov ax, KGDT_R3_CODE + RPL_MASK
-
-SetCs:
-    /* Set new CS */
-    mov [ebp+KTRAP_FRAME_CS], ax
-
-    /* Return success */
-    mov eax, 1
-    ret
-.endfunc
-
-.func OpcodeINTOV86
-_OpcodeINTOV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeIRETV86
-_OpcodeIRETV86:
-
-    /* Get the VDM State */
-    mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
-
-    /* Get flat ESP */
-    movzx ecx, word ptr [ebp+KTRAP_FRAME_SS]
-    shl ecx, 4
-    movzx edx, word ptr [ebp+KTRAP_FRAME_ESP]
-    add ecx, edx
-
-    /* Check for OPER32 prefix */
-    test ebx, PREFIX_FLAG_OPER32
-    jnz Iret32
-
-    /* Get flat IP */
-    movzx edi, word ptr [ecx]
-    mov [ebp+KTRAP_FRAME_EIP], edi
-    movzx esi, word ptr [ecx+2]
-    mov [ebp+KTRAP_FRAME_CS], esi
-
-    /* Update ESP */
-    add edx, 6
-    mov [ebp+KTRAP_FRAME_ESP], edx
-
-    /* Get EFLAGS */
-    movzx ebx, word ptr [ecx+4]
-
-MaskEFlags:
-
-    /* Mask out EFLAGS */
-    and ebx, ~(EFLAGS_IOPL + EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_VIP)
-    mov ecx, ebx
-
-    /* FIXME: Check for VME support */
-
-    /* Save VDM state */
-    push eax
-
-    /* Enable V86 and Interrupts */
-    or ebx, EFLAGS_V86_MASK + EFLAGS_INTERRUPT_MASK
-
-    /* Save old flags */
-    mov eax, [ebp+KTRAP_FRAME_EFLAGS]
-    push eax
-
-    /* Mask out VIP and set new eflags */
-    and eax, EFLAGS_VIP
-    or eax, ebx
-    mov [ebp+KTRAP_FRAME_EFLAGS], eax
-
-    /* Check if we have to update ESP0 */
-    pop ebx
-    test ebx, EFLAGS_V86_MASK
-    jnz NoEsp0Update
-
-    /* Save ECX and ECX */
-    push ecx
-    push edx
-
-    /* Update esp0 and restore registers */
-    push ebp
-    call _Ki386AdjustEsp0@4
-    pop edx
-    pop ecx
-
-NoEsp0Update:
-
-    /* Put VDM state in EAX and update VDM EFlags */
-    pop eax
-    and ecx, EFLAGS_INTERRUPT_MASK
-    LOCK and dword ptr [eax], ~EFLAGS_INTERRUPT_MASK
-    LOCK or [eax], ecx
-
-    /* Get flat EIP and check if this is the BOP */
-    shl esi, 4
-    add esi, edi
-    mov ax, [esi]
-    cmp ax, 0xC4C4
-    jz IsBop
-
-    /* FIXME: Check for VDM interrupts */
-
-    /* Return success */
-RetIret:
-    mov eax, 1
-    ret
-
-IsBop:
-
-    /* Call the BOP handler */
-    push ebp
-    call _VdmDispatchBop@4
-    jmp RetIret
-
-Iret32:
-
-    /* Get 32-bit flat EIP */
-    mov edi, [ecx]
-    mov [ebp+KTRAP_FRAME_EIP], edi
-    movzx esi, word ptr [ecx+4]
-    mov [ebp+KTRAP_FRAME_CS], esi
-
-    /* Set new ESP */
-    add edx, 12
-    mov [ebp+KTRAP_FRAME_ESP], edx
-
-    /* Get EFLAGS and continue */
-    mov ebx, [ecx+8]
-    jmp MaskEFlags
-.endfunc
-
-.func OpcodeNPXV86
-_OpcodeNPXV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeINBimmV86
-_OpcodeINBimmV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeINWimmV86
-_OpcodeINWimmV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeOUTBimmV86
-_OpcodeOUTBimmV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeOUTWimmV86
-_OpcodeOUTWimmV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeINBV86
-_OpcodeINBV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeINWV86
-_OpcodeINWV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeOUTBV86
-_OpcodeOUTBV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeOUTWV86
-_OpcodeOUTWV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
-.func OpcodeCLIV86
-_OpcodeCLIV86:
-
-    /* Get VDM State */
-    mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
-
-    /* FIXME: Support VME */
-
-    /* FIXME: Support VDM Interrupts */
-
-    /* Disable interrupts */
-    LOCK and dword ptr [eax], ~EFLAGS_INTERRUPT_MASK
-
-    /* Update EIP (remember EDI == instruction size) */
-    add [ebp+KTRAP_FRAME_EIP], edi
-
-    /* Return success */
-    mov eax, 1
-    ret
-.endfunc
-
-.func OpcodeSTIV86
-_OpcodeSTIV86:
-
-    /* Get VDM State */
-    mov eax, FIXED_NTVDMSTATE_LINEAR_PC_AT
-
-    /* FIXME: Support VME */
-
-    /* Enable interrupts */
-    LOCK or dword ptr [eax], EFLAGS_INTERRUPT_MASK
-
-    /* Update EIP (remember EDI == instruction size) */
-    add [ebp+KTRAP_FRAME_EIP], edi
-
-    /* FIXME: Support VDM Interrupts */
-
-    /* Return success */
-    mov eax, 1
-    ret
-.endfunc
-
-.func OpcodeGenericPrefixV86
-_OpcodeGenericPrefixV86:
-
-    /* Skip instruction */
-    inc esi
-    inc edi
-    
-    /* Get the instruction */
-    movzx ecx, byte ptr [esi]
-    
-    /* Get the opcode index */
-    movzx edx, byte ptr OpcodeIndex[ecx]
-    
-    /* Dispatch it */
-    jmp OpcodeDispatchV86[edx*4]
-.endfunc
-
-.func OpcodeHLTV86
-_OpcodeHLTV86:
-    UNHANDLED_V86_OPCODE
-.endfunc
-
 /* FUNCTIONS *****************************************************************/
 
 .globl _Ki386SetupAndExitToV86Mode@4
@@ -800,27 +192,3 @@ _Ki386BiosCallReturnAddress:
     pop ebp
     ret 4
 .endfunc
-
-.globl _Ki386HandleOpcodeV86@0
-.func Ki386HandleOpcodeV86@0
-_Ki386HandleOpcodeV86@0:
-
-    /* Get flat EIP */
-    mov esi, [ebp+KTRAP_FRAME_CS]
-    shl esi, 4
-    add esi, [ebp+KTRAP_FRAME_EIP]
-
-    /* Get the opcode entry in the table */
-    movzx ecx, byte ptr [esi]
-    movzx edx, byte ptr OpcodeIndex[ecx]
-
-    /* Set instruction length and prefix flags */
-    mov edi, 1
-    xor ebx, ebx
-
-    /* Accounting statistics */
-//    inc dword ptr _ExVdmOpcodeDispatchCounts[edx*4] // FIXME: Generates protection fault
-
-    /* Handle the opcode */
-    jmp OpcodeDispatchV86[edx*4]
-.endfunc
index 4814259..2a95411 100644 (file)
 /*
  * PROJECT:         ReactOS Kernel
- * LICENSE:         GPL - See COPYING in the top level directory
+ * LICENSE:         BSD - See COPYING.ARM in the top level directory
  * FILE:            ntoskrnl/ke/i386/v86vdm.c
- * PURPOSE:         Manages the Kernel's support for Virtual-8086 Mode (V86)
- *                  used by Video Drivers to access ROM BIOS functions, as well
- *                  as the kernel architecture part of generic VDM support.
- * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ * PURPOSE:         V8086 and VDM Trap Emulation
+ * PROGRAMMERS:     ReactOS Portable Systems Group
+ *                  Alex Ionescu (alex.ionescu@reactos.org)
  */
 
-/* INCLUDES ******************************************************************/
+/* INCLUDES *******************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
 #include <debug.h>
 
-/* GLOBALS *******************************************************************/
+/* GLOBALS ********************************************************************/
 
 ULONG KeI386EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE;
 ULONG KeI386EFlagsOrMaskV86 = EFLAGS_INTERRUPT_MASK;
 PVOID Ki386IopmSaveArea;
 BOOLEAN KeI386VirtualIntExtensions = FALSE;
 
-/* PRIVATE FUNCTIONS *********************************************************/
+#if 1
+const PULONG KiNtVdmState = (PULONG)FIXED_NTVDMSTATE_LINEAR_PC_AT;
 
-/* PUBLIC FUNCTIONS **********************************************************/
+/* UNHANDLED OPCODES **********************************************************/
+
+KiVdmUnhandledOpcode(F);
+KiVdmUnhandledOpcode(OUTSW);
+KiVdmUnhandledOpcode(OUTSB);
+KiVdmUnhandledOpcode(INSB);
+KiVdmUnhandledOpcode(INSW);
+KiVdmUnhandledOpcode(NPX);
+KiVdmUnhandledOpcode(INBimm);
+KiVdmUnhandledOpcode(INWimm);
+KiVdmUnhandledOpcode(OUTBimm);
+KiVdmUnhandledOpcode(OUTWimm);
+KiVdmUnhandledOpcode(INB);
+KiVdmUnhandledOpcode(INW);
+KiVdmUnhandledOpcode(OUTB);
+KiVdmUnhandledOpcode(OUTW);
+KiVdmUnhandledOpcode(HLT);
+KiVdmUnhandledOpcode(INTO);
+KiVdmUnhandledOpcode(INV);
+
+/* OPCODE HANDLERS ************************************************************/
+    
+BOOLEAN
+FASTCALL
+KiVdmOpcodePUSHF(IN PKTRAP_FRAME TrapFrame,
+                 IN ULONG Flags)
+{
+    ULONG Esp, V86EFlags, TrapEFlags;
+    
+    /* 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);
+    
+    /* Add in those flags if they exist, and add in the IOPL flag */
+    V86EFlags |= TrapEFlags;
+    V86EFlags |= EFLAGS_IOPL;
+    
+    /* Build flat ESP */
+    Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp;
+    Esp -= 2;
+    
+    /* Check for OPER32 */
+    if (Flags & PFX_FLAG_OPER32)
+    {
+        /* Save EFlags */
+        Esp -= 2;
+        *(PULONG)(Esp - 2) = V86EFlags;
+    }
+    else
+    {
+        /* Save EFLags */
+        *(PUSHORT)Esp = (USHORT)V86EFlags;
+    }
+    
+    /* Set new ESP and EIP */
+    TrapFrame->HardwareEsp = (USHORT)Esp;
+    TrapFrame->Eip += (Flags & 0xFF);
+    
+    /* We're done */
+    return TRUE;
+}
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodePOPF(IN PKTRAP_FRAME TrapFrame,
+                IN ULONG Flags)
+{
+    ULONG Esp, V86EFlags, EFlags, TrapEFlags;
+    
+    /* Build flat ESP */
+    Esp = (TrapFrame->HardwareSegSs << 4) + (USHORT)TrapFrame->HardwareEsp;
+    
+    /* Read EFlags */
+    EFlags = *(PULONG)Esp;
+    Esp += 4;
+    
+    /* Check for OPER32 */
+    if (!(Flags & PFX_FLAG_OPER32))
+    {
+        /* Read correct flags and use correct stack address */
+        Esp -= 2;
+        EFlags &= 0xFFFF;
+    }
+    
+    /* Set new ESP */
+    TrapFrame->HardwareEsp = Esp;
+    
+    /* Mask out IOPL from the flags */
+    EFlags &= ~EFLAGS_IOPL;
+    
+    /* Save the V86 flags, but mask out the nested task flag */
+    V86EFlags = EFlags & ~EFLAGS_NESTED_TASK;
+    
+    /* Now leave only alignment, nested task and interrupt flag */
+    EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
+    
+    /* FIXME: Check for VME support */
+    
+    /* 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;
+    
+    /* Check if ESP0 needs to be fixed up */
+    if (TrapEFlags & EFLAGS_V86_MASK) Ki386AdjustEsp0(TrapFrame);
+    
+    /* Update the V8086 EFlags state */
+    KiVdmClearVdmEFlags(EFLAGS_ALIGN_CHECK | EFLAGS_NESTED_TASK | EFLAGS_INTERRUPT_MASK);
+    KiVdmSetVdmEFlags(EFlags);
+   
+    /* FIXME: Check for VDM interrupts */
+    
+    /* Update EIP */
+    TrapFrame->Eip += (Flags & 0xFF);
+    
+    /* We're done */
+    return TRUE;
+}
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodeINTnn(IN PKTRAP_FRAME TrapFrame,
+                 IN ULONG Flags)
+{
+    ULONG Esp, V86EFlags, TrapEFlags, Eip, Interrupt;
+    
+    /* Read trap frame EFlags */
+    TrapEFlags = TrapFrame->EFlags;
+    
+    /* Remove interrupt flag from V8086 EFlags */
+    V86EFlags = *KiNtVdmState;
+    KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
+    
+    /* Keep only alignment and interrupt flag from the V8086 state */
+    V86EFlags &= (EFLAGS_ALIGN_CHECK | EFLAGS_INTERRUPT_MASK);
+    
+    /* FIXME: Support VME */
+    
+    /* Mask in the relevant V86 EFlags into the trap flags */
+    V86EFlags |= (TrapEFlags & ~EFLAGS_INTERRUPT_MASK);
+    
+    /* And mask out the VIF, nested task and TF flag from the trap flags */
+    TrapFrame->EFlags = TrapEFlags &~ (EFLAGS_VIF | EFLAGS_NESTED_TASK | EFLAGS_TF);
+    
+    /* Add the IOPL flag to the local trap flags */
+    V86EFlags |= EFLAGS_IOPL;
+    
+    /* Build flat ESP */
+    Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp;
+    
+    /* Push EFlags */
+    Esp -= 2;
+    *(PUSHORT)(Esp) = (USHORT)V86EFlags;
+    
+    /* Push CS */
+    Esp -= 2;
+    *(PUSHORT)(Esp) = (USHORT)TrapFrame->SegCs;
+    
+    /* Push IP */
+    Esp -= 2;
+    *(PUSHORT)(Esp) = (USHORT)TrapFrame->Eip + (Flags & 0xFF) + 1;
+    
+    /* Update ESP */
+    TrapFrame->HardwareEsp = (USHORT)Esp;
+    
+    /* Get flat EIP */
+    Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
+    
+    /* Now get the *next* EIP address (current is original + the count - 1) */
+    Eip += (Flags & 0xFF);
+    
+    /* Now read the interrupt number */
+    Interrupt = *(PUCHAR)Eip;
+    
+    /* Read the EIP from its IVT entry */
+    Interrupt = *(PULONG)(Interrupt * 4);
+    TrapFrame->Eip = (USHORT)Interrupt;
+    
+    /* Now get the CS segment */
+    Interrupt = (USHORT)(Interrupt >> 16);
+    
+    /* Check if the trap was not V8086 trap */
+    if (!(TrapFrame->EFlags & EFLAGS_V86_MASK))
+    {
+        /* Was it a kernel CS? */
+        Interrupt |= RPL_MASK;
+        if (TrapFrame->SegCs == KGDT_R0_CODE)
+        {
+            /* Add the RPL mask */
+            TrapFrame->SegCs = Interrupt;
+        }
+        else
+        {
+            /* Set user CS */
+            TrapFrame->SegCs = KGDT_R3_CODE | RPL_MASK;
+        }
+    }
+    else
+    {
+        /* Set IVT CS */
+        TrapFrame->SegCs = Interrupt;
+    }
+    
+    /* We're done */
+    return TRUE;
+}
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodeIRET(IN PKTRAP_FRAME TrapFrame,
+                IN ULONG Flags)
+{
+    ULONG Esp, V86EFlags, EFlags, TrapEFlags, Eip;
+    
+    /* Build flat ESP */
+    Esp = (TrapFrame->HardwareSegSs << 4) + TrapFrame->HardwareEsp;
+    
+    /* Check for OPER32 */
+    if (Flags & PFX_FLAG_OPER32)
+    {
+        /* Build segmented EIP */
+        TrapFrame->Eip = *(PULONG)Esp;
+        TrapFrame->SegCs = *(PUSHORT)(Esp + 4);
+        
+        /* Set new ESP */
+        TrapFrame->HardwareEsp += 12;
+        
+        /* Get EFLAGS */
+        EFlags = *(PULONG)(Esp + 8);
+    }
+    else
+    {
+        /* Build segmented EIP */
+        TrapFrame->Eip = *(PUSHORT)Esp;
+        TrapFrame->SegCs = *(PUSHORT)(Esp + 2);
+
+        /* Set new ESP */
+        TrapFrame->HardwareEsp += 6;
+
+        /* Get EFLAGS */
+        EFlags = *(PUSHORT)(Esp + 4);
+    }
+    
+    /* Mask out EFlags */
+    EFlags &= ~(EFLAGS_IOPL + EFLAGS_VIF + EFLAGS_NESTED_TASK + EFLAGS_VIP);
+    V86EFlags = EFlags;
+    
+    /* FIXME: Check for VME support */
+    
+    /* Add V86 and Interrupt flag */
+    EFlags |= EFLAGS_V86_MASK | EFLAGS_INTERRUPT_MASK;
+    
+    /* Update EFlags in trap frame */
+    TrapEFlags = TrapFrame->EFlags;
+    TrapFrame->EFlags = (TrapFrame->EFlags & EFLAGS_VIP) | EFlags;
+    
+    /* Check if ESP0 needs to be fixed up */
+    if (!(TrapEFlags & EFLAGS_V86_MASK)) Ki386AdjustEsp0(TrapFrame);
+    
+    /* Update the V8086 EFlags state */
+    KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
+    KiVdmSetVdmEFlags(V86EFlags);
+    
+    /* Build flat EIP and check if this is the BOP instruction */
+    Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
+    if (*(PUSHORT)Eip == 0xC4C4)
+    {
+        /* Dispatch the BOP */
+        VdmDispatchBop(TrapFrame);
+    }
+    else
+    {
+        /* FIXME: Check for VDM interrupts */
+    }
+    
+    /* We're done */
+    return TRUE;
+}
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodeCLI(IN PKTRAP_FRAME TrapFrame,
+               IN ULONG Flags)
+{       
+    /* FIXME: Support VME */
+
+    /* disable interrupts */
+    KiVdmClearVdmEFlags(EFLAGS_INTERRUPT_MASK);
+    
+    /* Skip instruction */
+    TrapFrame->Eip += (Flags & 0xFF);
+    
+    /* Done */
+    return TRUE;
+}
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodeSTI(IN PKTRAP_FRAME TrapFrame,
+               IN ULONG Flags)
+{
+    /* FIXME: Support VME */
+
+    /* Enable interrupts */
+    KiVdmSetVdmEFlags(EFLAGS_INTERRUPT_MASK);
+    
+    /* Skip instruction */
+    TrapFrame->Eip += (Flags & 0xFF);
+    
+    /* Done */
+    return TRUE;
+}
+
+/* MASTER OPCODE HANDLER ******************************************************/
+
+BOOLEAN
+FASTCALL
+KiVdmHandleOpcode(IN PKTRAP_FRAME TrapFrame,
+                  IN ULONG Flags)
+{
+    ULONG Eip;
+    
+    /* Get flat EIP of the *current* instruction (not the original EIP) */
+    Eip = (TrapFrame->SegCs << 4) + TrapFrame->Eip;
+    Eip += (Flags & 0xFF) - 1;
+    
+    /* Read the opcode entry */
+    switch (*(PUCHAR)Eip)
+    {
+        case 0xF:               return KiCallVdmHandler(F);
+        case 0x26:              return KiCallVdmPrefixHandler(PFX_FLAG_ES);
+        case 0x2E:              return KiCallVdmPrefixHandler(PFX_FLAG_CS);
+        case 0x36:              return KiCallVdmPrefixHandler(PFX_FLAG_SS);
+        case 0x3E:              return KiCallVdmPrefixHandler(PFX_FLAG_DS);
+        case 0x64:              return KiCallVdmPrefixHandler(PFX_FLAG_FS);
+        case 0x65:              return KiCallVdmPrefixHandler(PFX_FLAG_GS);
+        case 0x66:              return KiCallVdmPrefixHandler(PFX_FLAG_OPER32);
+        case 0x67:              return KiCallVdmPrefixHandler(PFX_FLAG_ADDR32);
+        case 0xF0:              return KiCallVdmPrefixHandler(PFX_FLAG_LOCK);
+        case 0xF2:              return KiCallVdmPrefixHandler(PFX_FLAG_REPNE);
+        case 0xF3:              return KiCallVdmPrefixHandler(PFX_FLAG_REP);
+        case 0x6C:              return KiCallVdmHandler(INSB);
+        case 0x6D:              return KiCallVdmHandler(INSW);
+        case 0x6E:              return KiCallVdmHandler(OUTSB);
+        case 0x6F:              return KiCallVdmHandler(OUTSW);
+        case 0x98:              return KiCallVdmHandler(NPX);
+        case 0xD8:              return KiCallVdmHandler(NPX);
+        case 0xD9:              return KiCallVdmHandler(NPX);
+        case 0xDA:              return KiCallVdmHandler(NPX);
+        case 0xDB:              return KiCallVdmHandler(NPX);
+        case 0xDC:              return KiCallVdmHandler(NPX);
+        case 0xDD:              return KiCallVdmHandler(NPX);
+        case 0xDE:              return KiCallVdmHandler(NPX);
+        case 0xDF:              return KiCallVdmHandler(NPX);
+        case 0x9C:              return KiCallVdmHandler(PUSHF);
+        case 0x9D:              return KiCallVdmHandler(POPF);
+        case 0xCD:              return KiCallVdmHandler(INTnn);
+        case 0xCE:              return KiCallVdmHandler(INTO);
+        case 0xCF:              return KiCallVdmHandler(IRET);   
+        case 0xE4:              return KiCallVdmHandler(INBimm);   
+        case 0xE5:              return KiCallVdmHandler(INWimm);
+        case 0xE6:              return KiCallVdmHandler(OUTBimm);
+        case 0xE7:              return KiCallVdmHandler(OUTWimm);        
+        case 0xEC:              return KiCallVdmHandler(INB);
+        case 0xED:              return KiCallVdmHandler(INW);
+        case 0xEE:              return KiCallVdmHandler(OUTB);
+        case 0xEF:              return KiCallVdmHandler(OUTW);
+        case 0xF4:              return KiCallVdmHandler(HLT);
+        case 0xFA:              return KiCallVdmHandler(CLI);
+        case 0xFB:              return KiCallVdmHandler(STI);
+        default:                return KiCallVdmHandler(INV);
+    }    
+}
+
+/* PREFIX HANDLER *************************************************************/
+
+BOOLEAN
+FASTCALL
+KiVdmOpcodePrefix(IN PKTRAP_FRAME TrapFrame,
+                  IN ULONG Flags)
+{
+    /* Increase instruction size */
+    Flags++;
+    
+    /* Handle the next opcode */
+    return KiVdmHandleOpcode(TrapFrame, Flags);
+}
+
+/* TRAP HANDLER ***************************************************************/
+
+BOOLEAN
+FASTCALL
+Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame)
+{
+    /* Clean up */
+    TrapFrame->Eip &= 0xFFFF;
+    TrapFrame->HardwareEsp &= 0xFFFF;
+
+    /* We start with only 1 byte per instruction */
+    return KiVdmHandleOpcode(TrapFrame, 1);
+}
+
+/* PUBLIC FUNCTIONS ***********************************************************/
+#endif
 
 /*
  * @implemented