.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
ULONG KeI386EFlagsOrMaskV86 = EFLAGS_INTERRUPT_MASK;
PVOID Ki386IopmSaveArea;
BOOLEAN KeI386VirtualIntExtensions = FALSE;
-
-#if 1
const PULONG KiNtVdmState = (PULONG)FIXED_NTVDMSTATE_LINEAR_PC_AT;
/* UNHANDLED OPCODES **********************************************************/
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