[NTOS]: Rewrite BIOS Call (V8086) Entry/Exit routines in C. Only 4 lines of ASM stub...
authorSir Richard <sir_richard@svn.reactos.org>
Mon, 11 Jan 2010 03:47:17 +0000 (03:47 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Mon, 11 Jan 2010 03:47:17 +0000 (03:47 +0000)
svn path=/trunk/; revision=45037

reactos/ntoskrnl/include/internal/i386/ke.h
reactos/ntoskrnl/include/internal/trap_x.h
reactos/ntoskrnl/ke/i386/v86m_sup.S
reactos/ntoskrnl/ke/i386/v86vdm.c
reactos/ntoskrnl/vdm/vdmexec.c

index abcaba7..200a843 100644 (file)
@@ -139,6 +139,27 @@ typedef union _KTRAP_EXIT_SKIP_BITS
         return TRUE;                                \
     }
 
+C_ASSERT(NPX_FRAME_LENGTH == sizeof(FX_SAVE_AREA));
+
+//
+// Local parameters
+//
+typedef struct _KV86_FRAME
+{
+    PVOID ThreadStack;
+    PVOID ThreadTeb;
+    PVOID PcrTeb;
+} KV86_FRAME, *PKV86_FRAME;
+
+//
+// Virtual Stack Frame
+//
+typedef struct _KV8086_STACK_FRAME
+{
+    KTRAP_FRAME TrapFrame;
+    FX_SAVE_AREA NpxArea;
+    KV86_FRAME V86Frame;
+} KV8086_STACK_FRAME, *PKV8086_STACK_FRAME;
               
 //
 // Registers an interrupt handler with an IDT vector
@@ -382,6 +403,12 @@ Ki386HandleOpcodeV86(
     IN PKTRAP_FRAME TrapFrame
 );
 
+VOID
+FASTCALL
+KiEoiHelper(
+    IN PKTRAP_FRAME TrapFrame
+);
+
 //
 // Global x86 only Kernel data
 //
@@ -409,6 +436,14 @@ extern VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
 extern VOID __cdecl CopyParams(VOID);
 extern VOID __cdecl ReadBatch(VOID);
 extern VOID __cdecl FrRestore(VOID);
+extern VOID Ki386BiosCallReturnAddress(VOID);
+
+PFX_SAVE_AREA
+FORCEINLINE
+KiGetThreadNpxArea(IN PKTHREAD Thread)
+{
+    return (PFX_SAVE_AREA)((ULONG_PTR)Thread->InitialStack - sizeof(FX_SAVE_AREA));
+}
 
 //
 // Sanitizes a selector
index 898bba0..a519123 100644 (file)
@@ -137,13 +137,6 @@ KiVdmTrap(IN PKTRAP_FRAME TrapFrame)
             ((KiUserTrap(TrapFrame)) && (PsGetCurrentProcess()->VdmObjects)));
 }
 
-PFX_SAVE_AREA
-FORCEINLINE
-KiGetThreadNpxArea(IN PKTHREAD Thread)
-{
-    return (PFX_SAVE_AREA)((ULONG_PTR)Thread->InitialStack - sizeof(FX_SAVE_AREA));
-}
-
 VOID
 FORCEINLINE
 KiTrapFrameFromPushaStack(IN PKTRAP_FRAME TrapFrame)
index 1744023..fd4d58b 100644 (file)
 .func Ki386SetupAndExitToV86Mode@4
 _Ki386SetupAndExitToV86Mode@4:
 
-    /* Save nonvolatiles */
-    push ebp
-    push ebx
-    push esi
-    push edi
-
-    /* Give us a little stack */
-    sub esp, 12
-    mov ecx, esp
-
-    /* Go past the KTRAP_FRAME and NPX Frame and set a new frame in EAX */
-    sub esp, NPX_FRAME_LENGTH
-    and esp, ~15
-    sub esp, KTRAP_FRAME_LENGTH
-    mov eax, esp
-
-    /* Create a fake user-mode frame */
-    mov dword ptr [eax+KTRAP_FRAME_CS], KGDT_R0_CODE + RPL_MASK
-    mov dword ptr [eax+KTRAP_FRAME_ES], 0
-    mov dword ptr [eax+KTRAP_FRAME_DS], 0
-    mov dword ptr [eax+KTRAP_FRAME_FS], 0
-    mov dword ptr [eax+KTRAP_FRAME_GS], 0
-    mov dword ptr [eax+KTRAP_FRAME_ERROR_CODE], 0
-
-    /* Get the current thread's initial stack */
-    mov ebx, [fs:KPCR_SELF]
-    mov edi, [ebx+KPCR_CURRENT_THREAD]
-    mov edx, [edi+KTHREAD_INITIAL_STACK]
-    sub edx, NPX_FRAME_LENGTH
-
-    /* Save it on our stack, as well as the real TEB addresses */
-    mov [ecx], edx
-    mov edx, [edi+KTHREAD_TEB]
-    mov [ecx+4], edx
-    mov edx, [fs:KPCR_TEB]
-    mov [ecx+8] , edx
-
-    /* Set our ESP in ESI, and the return function in EIP */
-    mov edi, offset _Ki386BiosCallReturnAddress
-    mov [eax+KTRAP_FRAME_ESI], ecx
-    mov [eax+KTRAP_FRAME_EIP], edi
-
-    /* Push the flags and sanitize them */
-    pushfd
-    pop edi
-    and edi, 0x60DD7
-    or edi, EFLAGS_INTERRUPT_MASK
-
-    /* Set SS and ESP, and fill out the rest of the frame */
-    mov dword ptr [eax+KTRAP_FRAME_SS], KGDT_R3_DATA + RPL_MASK;
-    mov dword ptr [eax+KTRAP_FRAME_ESP], 0x11FFE;
-    mov dword ptr [eax+KTRAP_FRAME_EFLAGS], edi
-    mov dword ptr [eax+KTRAP_FRAME_EXCEPTION_LIST], -1
-    mov dword ptr [eax+KTRAP_FRAME_PREVIOUS_MODE], -1
-    mov dword ptr [eax+KTRAP_FRAME_DR7], 0
-    mov dword ptr [eax+KTRAP_FRAME_DEBUGARGMARK], 0xBADB0D00
-
-    /* Jump past the frame now */
-    add eax, KTRAP_FRAME_LENGTH
-    cli
-
-    /* Save the current stack */
-    push ecx
-
-    /* Get the current thread's intial stack again */
-    mov edi, [ebx+KPCR_CURRENT_THREAD]
-    mov esi, [edi+KTHREAD_INITIAL_STACK]
-    sub esi, NPX_FRAME_LENGTH
-
-    /* Set the size of the copy, and the destination, and copy the NPX frame */
-    mov ecx, NPX_FRAME_LENGTH / 4
-    mov edi, eax
-    rep movsd
-
-    /* Restore stack */
-    pop ecx
-
-    /* Get the current thread and TSS */
-    mov edi, [ebx+KPCR_CURRENT_THREAD]
-    mov esi, [ebx+KPCR_TSS]
-
-    /* Bias the V86 vrame */
-    sub eax, KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS
-
-    /* Set exception list and new ESP */
-    mov dword ptr [ebx+KPCR_EXCEPTION_LIST], -1
-    mov [esi+KTSS_ESP0], eax
-
-    /* Now skip past the NPX frame and V86 fields and set this as the intial stack */
-    add eax, NPX_FRAME_LENGTH + (KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS)
-    mov [edi+KTHREAD_INITIAL_STACK], eax
-
-    /* Setup our fake TEB pointer */
-    mov eax, [ecx+0x20]
-    mov [fs:KPCR_TEB], eax
-    mov [edi+KTHREAD_TEB], eax
-
-    /* Setup the descriptors for the fake TEB */
-    mov ebx, [fs:KPCR_GDT]
-    mov [ebx+0x3A], ax
-    shr eax, 16
-    mov [ebx+0x3C], al
-    mov [ebx+0x3F], ah
-    sti
-
-    /*
-     * Start VDM execution. This will save this fake 32-bit KTRAP_FRAME and
-     * initialize a real 16-bit VDM context frame
-     */
-    push 0
-    push 0 // VdmStartExecution
-    call _NtVdmControl@8
-
-    /* Exit to V86 mode */
-    mov ebp, esp
-    jmp _Kei386EoiHelper@0
+    /* Enter V8086 mode */
+    pushad
+    call @KiEnterV86Mode@0
 .endfunc
 
 .globl _Ki386BiosCallReturnAddress
 .func Ki386BiosCallReturnAddress
 _Ki386BiosCallReturnAddress:
 
-    /* Get the PCR */
-    mov eax, [fs:KPCR_SELF]
-
-    /* Get NPX destination */
-    mov edi, [ebp+KTRAP_FRAME_ESI]
-    mov edi, [edi]
-
-    /* Get initial stack */
-    mov ecx, [eax+KPCR_CURRENT_THREAD]
-    mov esi, [ecx+KTHREAD_INITIAL_STACK]
-    sub esi, NPX_FRAME_LENGTH
-
-    /* Set length and copy the NPX frame */
-    mov ecx, NPX_FRAME_LENGTH / 4
-    rep movsd
-
-    /* Restore stack */
-    mov esp, [ebp+KTRAP_FRAME_ESI]
-    add esp, 4
-
-    /* Set initial stack */
-    mov ecx, [eax+KPCR_CURRENT_THREAD]
-    mov [ecx+KTHREAD_INITIAL_STACK], edi
-
-    /* Get TSS and set the ESP 0 */
-    mov eax, [eax+KPCR_TSS]
-    sub edi, NPX_FRAME_LENGTH + (KTRAP_FRAME_V86_GS - KTRAP_FRAME_SS)
-    mov [eax+KTSS_ESP0], edi
-
-    /* Restore KTHREAD TEB in EDX */
-    pop edx
-    mov [ecx+KTHREAD_TEB], edx
-
-    /* Restore PCR TEB in EDX */
-    pop edx
-    mov [fs:KPCR_TEB], edx
+    /* Exit V8086 mode */
+    mov ecx, ebp
+    call @KiExitV86Mode@4
+    mov esp, eax
+    popad
+.endfunc
 
-    /* Setup the descriptors for the real TEB */
-    mov ebx, [fs:KPCR_GDT]
-    mov [ebx+0x3A], dx
-    shr edx, 16
-    mov [ebx+0x3C], dl
-    mov [ebx+0x3F], dh
 
-    /* Enable interrupts and pop back non-volatiles */
-    sti
-    pop edi
-    pop esi
-    pop ebx
-    pop ebp
-    ret 4
-.endfunc
index 2a95411..8e587bd 100644 (file)
@@ -19,8 +19,6 @@ ULONG KeI386EFlagsAndMaskV86 = EFLAGS_USER_SANITIZE;
 ULONG KeI386EFlagsOrMaskV86 = EFLAGS_INTERRUPT_MASK;
 PVOID Ki386IopmSaveArea;
 BOOLEAN KeI386VirtualIntExtensions = FALSE;
-
-#if 1
 const PULONG KiNtVdmState = (PULONG)FIXED_NTVDMSTATE_LINEAR_PC_AT;
 
 /* UNHANDLED OPCODES **********************************************************/
@@ -431,8 +429,128 @@ Ki386HandleOpcodeV86(IN PKTRAP_FRAME TrapFrame)
     return KiVdmHandleOpcode(TrapFrame, 1);
 }
 
+ULONG_PTR
+FASTCALL
+KiExitV86Mode(IN PKTRAP_FRAME TrapFrame)
+{
+    PKV8086_STACK_FRAME StackFrame;
+    PKGDTENTRY GdtEntry;
+    PKTHREAD Thread;
+    PKTRAP_FRAME PmTrapFrame;
+    PKV86_FRAME V86Frame;
+    PFX_SAVE_AREA NpxFrame;
+    
+    /* Get the stack frame back */
+    StackFrame = CONTAINING_RECORD(TrapFrame->Esi, KV8086_STACK_FRAME, V86Frame);
+    PmTrapFrame = &StackFrame->TrapFrame;
+    V86Frame = &StackFrame->V86Frame;
+    NpxFrame = &StackFrame->NpxArea;
+    
+    /* Copy the FPU frame back */
+    Thread = KeGetCurrentThread();
+    RtlCopyMemory(KiGetThreadNpxArea(Thread), NpxFrame, sizeof(FX_SAVE_AREA));
+
+    /* Set initial stack back */
+    Thread->InitialStack = (PVOID)((ULONG_PTR)V86Frame->ThreadStack + sizeof(FX_SAVE_AREA));
+    
+    /* Set ESP0 back in the KTSS */
+    KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&PmTrapFrame->V86Es;
+
+    /* Restore TEB addresses */
+    Thread->Teb = V86Frame->ThreadTeb;
+    KeGetPcr()->Tib.Self = V86Frame->PcrTeb;
+    
+    /* Setup real TEB descriptor */
+    GdtEntry = &((PKIPCR)KeGetPcr())->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)];
+    GdtEntry->BaseLow = (USHORT)((ULONG_PTR)Thread->Teb & 0xFFFF);
+    GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)Thread->Teb >> 16);
+    GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)Thread->Teb >> 24);
+
+    /* Enable interrupts and pop back non-volatiles */
+    _enable();
+    return TrapFrame->Edi;
+}
+
+VOID
+FASTCALL
+KiEnterV86Mode(VOID)
+{
+    PKTHREAD Thread;
+    PKGDTENTRY GdtEntry;
+    KV8086_STACK_FRAME StackFrameBuffer;
+    PKV8086_STACK_FRAME StackFrame = &StackFrameBuffer;
+    PKTRAP_FRAME TrapFrame = &StackFrame->TrapFrame;
+    PKV86_FRAME V86Frame = &StackFrame->V86Frame;
+    PFX_SAVE_AREA NpxFrame = &StackFrame->NpxArea;
+
+    /* Build fake user-mode trap frame */
+    TrapFrame->SegCs = KGDT_R0_CODE | RPL_MASK;
+    TrapFrame->SegEs = TrapFrame->SegDs = TrapFrame->SegFs = TrapFrame->SegGs = 0;
+    TrapFrame->ErrCode = 0;
+    
+    /* Get the current thread's initial stack */
+    Thread = KeGetCurrentThread();
+    V86Frame->ThreadStack = KiGetThreadNpxArea(Thread);
+    
+    /* Save TEB addresses */
+    V86Frame->ThreadTeb = Thread->Teb;
+    V86Frame->PcrTeb = KeGetPcr()->Tib.Self;
+    
+    /* Save return EIP */
+    TrapFrame->Eip = (ULONG_PTR)Ki386BiosCallReturnAddress;
+    
+    /* Save our stack (after the frames) */
+    TrapFrame->Esi = (ULONG_PTR)V86Frame;
+    TrapFrame->Edi = (ULONG_PTR)_AddressOfReturnAddress() + 4;
+    
+    /* Sanitize EFlags and enable interrupts */
+    TrapFrame->EFlags = __readeflags() & 0x60DD7;
+    TrapFrame->EFlags |= EFLAGS_INTERRUPT_MASK;
+    
+    /* Fill out the rest of the frame */
+    TrapFrame->HardwareSegSs = KGDT_R3_DATA | RPL_MASK;
+    TrapFrame->HardwareEsp = 0x11FFE;
+    TrapFrame->ExceptionList = EXCEPTION_CHAIN_END;
+    TrapFrame->Dr7 = 0;
+    //TrapFrame->DbgArgMark = 0xBADB0D00;
+    TrapFrame->PreviousPreviousMode = -1;
+    
+    /* Disable interrupts */
+    _disable();
+    
+    /* Copy the thread's NPX frame */
+    RtlCopyMemory(NpxFrame, V86Frame->ThreadStack, sizeof(FX_SAVE_AREA));
+    
+    /* Clear exception list */
+    KeGetPcr()->Tib.ExceptionList = EXCEPTION_CHAIN_END;
+    
+    /* Set new ESP0 */
+    KeGetPcr()->TSS->Esp0 = (ULONG_PTR)&TrapFrame->V86Es;
+                             
+    /* Set new initial stack */
+    Thread->InitialStack = V86Frame;
+        
+    /* Set VDM TEB */
+    Thread->Teb = (PTEB)TRAMPOLINE_TEB;
+    KeGetPcr()->Tib.Self = (PVOID)TRAMPOLINE_TEB;
+    
+    /* Setup VDM TEB descriptor */
+    GdtEntry = &((PKIPCR)KeGetPcr())->GDT[KGDT_R3_TEB / sizeof(KGDTENTRY)];
+    GdtEntry->BaseLow = (USHORT)((ULONG_PTR)TRAMPOLINE_TEB & 0xFFFF);
+    GdtEntry->HighWord.Bytes.BaseMid = (UCHAR)((ULONG_PTR)TRAMPOLINE_TEB >> 16);
+    GdtEntry->HighWord.Bytes.BaseHi = (UCHAR)((ULONG_PTR)TRAMPOLINE_TEB >> 24);
+    
+    /* Enable interrupts */
+    _enable();
+    /* Start VDM execution */
+    NtVdmControl(VdmStartExecution, NULL);
+    
+    /* Exit to V86 mode */
+    KiEoiHelper(TrapFrame);
+}
 /* PUBLIC FUNCTIONS ***********************************************************/
-#endif
 
 /*
  * @implemented
index d54974a..067c1cc 100644 (file)
@@ -50,7 +50,7 @@ VdmSwapContext(IN PKTRAP_FRAME TrapFrame,
 
     /* Make sure that we're at APC_LEVEL and that this is a valid frame */
     ASSERT(KeGetCurrentIrql() == APC_LEVEL);
-    ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
+    //ASSERT(TrapFrame->DbgArgMark == 0xBADB0D00);
 
     /* Check if this is a V86 frame */
     if (TrapFrame->EFlags & EFLAGS_V86_MASK)