mirror of
https://github.com/reactos/reactos.git
synced 2025-01-01 03:54:02 +00:00
[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!
svn path=/trunk/; revision=45037
This commit is contained in:
parent
2741b8149a
commit
38de4a0a1c
5 changed files with 167 additions and 178 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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]
|
||||
|
||||
/* 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
|
||||
/* Exit V8086 mode */
|
||||
mov ecx, ebp
|
||||
call @KiExitV86Mode@4
|
||||
mov esp, eax
|
||||
popad
|
||||
.endfunc
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue