Author: sir_richard
Date: Mon Jan 11 04:47:17 2010
New Revision: 45037
URL:
http://svn.reactos.org/svn/reactos?rev=45037&view=rev
Log:
[NTOS]: Rewrite BIOS Call (V8086) Entry/Exit routines in C. Only 4 lines of ASM stub
remain. This wasn't fun... the stack dancing alone gives you headaches. Who ever
thought of dynamically sized trap frames!
Modified:
trunk/reactos/ntoskrnl/include/internal/i386/ke.h
trunk/reactos/ntoskrnl/include/internal/trap_x.h
trunk/reactos/ntoskrnl/ke/i386/v86m_sup.S
trunk/reactos/ntoskrnl/ke/i386/v86vdm.c
trunk/reactos/ntoskrnl/vdm/vdmexec.c
Modified: trunk/reactos/ntoskrnl/include/internal/i386/ke.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/i386/ke.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/i386/ke.h [iso-8859-1] Mon Jan 11 04:47:17
2010
@@ -139,6 +139,27 @@
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
@@ -379,6 +400,12 @@
BOOLEAN
FASTCALL
Ki386HandleOpcodeV86(
+ IN PKTRAP_FRAME TrapFrame
+);
+
+VOID
+FASTCALL
+KiEoiHelper(
IN PKTRAP_FRAME TrapFrame
);
@@ -409,6 +436,14 @@
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
Modified: trunk/reactos/ntoskrnl/include/internal/trap_x.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/trap_x.h [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/include/internal/trap_x.h [iso-8859-1] Mon Jan 11 04:47:17
2010
@@ -137,13 +137,6 @@
((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)
Modified: trunk/reactos/ntoskrnl/ke/i386/v86m_sup.S
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/v86m_sup.…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/v86m_sup.S [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/v86m_sup.S [iso-8859-1] Mon Jan 11 04:47:17 2010
@@ -18,177 +18,20 @@
.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]
+ /* Exit V8086 mode */
+ mov ecx, ebp
+ call @KiExitV86Mode@4
+ mov esp, eax
+ popad
+.endfunc
- /* 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
-
- /* 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
Modified: trunk/reactos/ntoskrnl/ke/i386/v86vdm.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ke/i386/v86vdm.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/ke/i386/v86vdm.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/ke/i386/v86vdm.c [iso-8859-1] Mon Jan 11 04:47:17 2010
@@ -19,8 +19,6 @@
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 @@
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
Modified: trunk/reactos/ntoskrnl/vdm/vdmexec.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/vdm/vdmexec.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/vdm/vdmexec.c [iso-8859-1] (original)
+++ trunk/reactos/ntoskrnl/vdm/vdmexec.c [iso-8859-1] Mon Jan 11 04:47:17 2010
@@ -50,7 +50,7 @@
/* 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)