Trap Handlers in C Patch 3 of X (Patch by Sir_Richard <ros.arm@reactos.org>):

[NTOS]: Fix a bug in the assertion handler.
    [NTOS]: Implement page fault trap (14) in C instead of ASM.
    [NTOS]: Implement V8086 trap entry/exit, we were hitting these during page faults in Ke386CallBios for video reset during GUI boot.

svn path=/trunk/; revision=45005
This commit is contained in:
Sir Richard 2010-01-08 18:21:47 +00:00
parent b308ece644
commit 8323208ddf
3 changed files with 157 additions and 215 deletions

View file

@ -9,7 +9,6 @@
//
// Debug Macros
//
#if YDEBUG
VOID
NTAPI
KiDumpTrapFrame(IN PKTRAP_FRAME TrapFrame)
@ -52,6 +51,7 @@ KiDumpTrapFrame(IN PKTRAP_FRAME TrapFrame)
DPRINT1("V86Gs: %x\n", TrapFrame->V86Gs);
}
#if YDEBUG
FORCEINLINE
VOID
KiFillTrapFrameDebug(IN PKTRAP_FRAME TrapFrame)
@ -220,6 +220,18 @@ KiDispatchException0Args(IN NTSTATUS Code,
KiDispatchExceptionFromTrapFrame(Code, Address, 0, 0, 0, 0, TrapFrame);
}
VOID
FORCEINLINE
KiDispatchException2Args(IN NTSTATUS Code,
IN ULONG_PTR Address,
IN ULONG P1,
IN ULONG P2,
IN PKTRAP_FRAME TrapFrame)
{
/* Helper for exceptions with no arguments */
KiDispatchExceptionFromTrapFrame(Code, Address, 2, P1, P2, 0, TrapFrame);
}
FORCEINLINE
VOID
KiTrapReturn(IN PKTRAP_FRAME TrapFrame)

View file

@ -58,6 +58,10 @@ GENERATE_IDT_STUBS /* INT 30-FF: UNEXPECTED INTERRUPTS */
.globl _KiTrap8
.globl _KiTrap19
/* System call code referenced from C code */
.globl _CopyParams
.globl _ReadBatch
/* System call entrypoints: */
.globl _KiFastCallEntry
.globl _KiSystemService
@ -193,7 +197,7 @@ SharedCode:
/* Check if we should flush the User Batch */
xor ebx, ebx
ReadBatch:
_ReadBatch:
or ebx, [ecx+TEB_GDI_BATCH_COUNT]
jz NotWin32K
@ -239,7 +243,7 @@ NoCountTable:
cmp esi, _MmUserProbeAddress
jnb AccessViolation
CopyParams:
_CopyParams:
/* Copy the parameters */
rep movsd
@ -359,7 +363,7 @@ AccessViolation:
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
/* It's fine, go ahead with it */
jz CopyParams
jz _CopyParams
/* Caller sent invalid parameters, fail here */
mov eax, STATUS_ACCESS_VIOLATION
@ -1219,9 +1223,9 @@ NotV86:
test dword ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
jnz UserModeGpf
/* Check if we have a VDM alert */
cmp dword ptr PCR[KPCR_VDM_ALERT], 0
jnz VdmAlertGpf
///* Check if we have a VDM alert */
//cmp dword ptr PCR[KPCR_VDM_ALERT], 0 // BUGBUG: Add this back later
//jnz VdmAlertGpf
/* Check for GPF during GPF */
mov eax, [ebp+KTRAP_FRAME_EIP]
@ -1607,203 +1611,7 @@ DispatchV86Gpf:
UNHANDLED_V86_PATH
.endfunc
.func KiTrap14
TRAP_FIXUPS kite_a, kite_t, DoFixupV86, DoNotFixupAbios
_KiTrap14:
/* Enter trap */
TRAP_PROLOG kite_a, kite_t
/* Check if we have a VDM alert */
cmp dword ptr PCR[KPCR_VDM_ALERT], 0
jnz VdmAlertGpf
/* Get the current thread */
mov edi, PCR[KPCR_CURRENT_THREAD]
/* Get the stack address of the frame */
lea eax, [esp+KTRAP_FRAME_LENGTH+NPX_FRAME_LENGTH]
sub eax, [edi+KTHREAD_INITIAL_STACK]
jz NoFixUp
/* This isn't the base frame, check if it's the second */
cmp eax, -KTRAP_FRAME_EFLAGS
jb NoFixUp
/* Check if we have a TEB */
mov eax, PCR[KPCR_TEB]
or eax, eax
jle NoFixUp
/* Fixup the frame */
call _KiFixupFrame
/* Save CR2 */
NoFixUp:
mov edi, cr2
/* Check if this processor has the cmpxchg8b lock errata */
cmp byte ptr _KiI386PentiumLockErrataPresent, 0
jnz HandleLockErrata
NotLockErrata:
/* HACK: Handle page faults with interrupts disabled */
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
je HandlePf
/* Enable interrupts and check if we got here with interrupts disabled */
sti
#ifdef HACK_ABOVE_FIXED
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_INTERRUPT_MASK
jz IllegalState
#endif
HandlePf:
/* Send trap frame and check if this is kernel-mode or usermode */
push ebp
mov eax, [ebp+KTRAP_FRAME_CS]
and eax, MODE_MASK
push eax
/* Send faulting address and check if this is read or write */
push edi
mov eax, [ebp+KTRAP_FRAME_ERROR_CODE]
and eax, 1
push eax
/* Call the access fault handler */
call _MmAccessFault@16
test eax, eax
jl AccessFail
/* Access fault handled, return to caller */
jmp _Kei386EoiHelper@0
AccessFail:
/* First check if this is a fault in the S-LIST functions */
mov ecx, offset _ExpInterlockedPopEntrySListFault@0
cmp [ebp+KTRAP_FRAME_EIP], ecx
jz SlistFault
/* Check if this is a fault in the syscall handler */
mov ecx, offset CopyParams
cmp [ebp+KTRAP_FRAME_EIP], ecx
jz SysCallCopyFault
mov ecx, offset ReadBatch
cmp [ebp+KTRAP_FRAME_EIP], ecx
jnz CheckVdmPf
/* FIXME: TODO */
UNHANDLED_PATH "SYSENTER Fault"
jmp _Kei386EoiHelper@0
SysCallCopyFault:
/* FIXME: TODO */
UNHANDLED_PATH "SYSENTER Fault"
jmp _Kei386EoiHelper@0
/* Check if the fault occured in a V86 mode */
CheckVdmPf:
mov ecx, [ebp+KTRAP_FRAME_ERROR_CODE]
shr ecx, 1
and ecx, 1
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jnz VdmPF
/* Check if the fault occured in a VDM */
mov esi, PCR[KPCR_CURRENT_THREAD]
mov esi, [esi+KTHREAD_APCSTATE_PROCESS]
cmp dword ptr [esi+EPROCESS_VDM_OBJECTS], 0
jz CheckStatus
/* Check if we this was in kernel-mode */
test byte ptr [ebp+KTRAP_FRAME_CS], MODE_MASK
jz CheckStatus
cmp word ptr [ebp+KTRAP_FRAME_CS], KGDT_R3_CODE + RPL_MASK
jz CheckStatus
VdmPF:
/* FIXME: TODO */
UNHANDLED_V86_PATH
/* Save EIP and check what kind of status failure we got */
CheckStatus:
mov esi, [ebp+KTRAP_FRAME_EIP]
cmp eax, STATUS_ACCESS_VIOLATION
je AccessViol
cmp eax, STATUS_GUARD_PAGE_VIOLATION
je SpecialCode
cmp eax, STATUS_STACK_OVERFLOW
je SpecialCode
/* Setup an in-page exception to dispatch */
mov edx, ecx
mov ebx, esi
mov esi, edi
mov ecx, 3
mov edi, eax
mov eax, STATUS_IN_PAGE_ERROR
call _CommonDispatchException
AccessViol:
/* Use more proper status code */
mov eax, KI_EXCEPTION_ACCESS_VIOLATION
SpecialCode:
/* Setup a normal page fault exception */
mov ebx, esi
mov edx, ecx
mov esi, edi
jmp _DispatchTwoParam
SlistFault:
/* FIXME: TODO */
UNHANDLED_PATH "SLIST Fault"
IllegalState:
/* This is completely illegal, bugcheck the system */
push ebp
push esi
push ecx
push eax
push edi
push IRQL_NOT_LESS_OR_EQUAL
call _KeBugCheckWithTf@24
VdmAlertGpf:
/* FIXME: NOT SUPPORTED */
UNHANDLED_V86_PATH
HandleLockErrata:
/* Fail if this isn't a write fault */
test word ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0x4
jnz NotLockErrata
/* Also make sure the page fault is for IDT entry 6 */
mov eax, PCR[KPCR_IDT]
add eax, 0x30
cmp eax, edi
jne NotLockErrata
/*
* This is a write fault to the Invalid Opcode handler entry.
* We assume this is the lock errata and not a real write fault.
*/
/* Clear the error code */
and dword ptr [ebp+KTRAP_FRAME_ERROR_CODE], 0
/* Check if this happened in V86 mode */
test dword ptr [ebp+KTRAP_FRAME_EFLAGS], EFLAGS_V86_MASK
jnz VdmOpCodeFault
/* Dispatch this to the invalid opcode handler */
jmp DispatchLockErrata
.endfunc
GENERATE_TRAP_HANDLER KiTrap14, 0
GENERATE_TRAP_HANDLER KiTrap0F, 1
.func KiTrap16

View file

@ -43,13 +43,8 @@ KiExitTrap(IN PKTRAP_FRAME TrapFrame,
}
/* Check if this was a V8086 trap */
if (TrapFrame->EFlags & EFLAGS_V86_MASK)
{
/* Not handled yet */
UNIMPLEMENTED;
while (TRUE);
}
if (TrapFrame->EFlags & EFLAGS_V86_MASK) KiTrapReturn(TrapFrame);
/* Check if the trap frame was edited */
if (!(TrapFrame->SegCs & FRAME_EDITED))
{
@ -155,8 +150,11 @@ KiEnterTrap(IN PKTRAP_FRAME TrapFrame)
/* Check for V86 mode */
if (TrapFrame->EFlags & EFLAGS_V86_MASK)
{
UNIMPLEMENTED;
while (TRUE);
/* Restore V8086 segments into Protected Mode segments */
TrapFrame->SegFs = TrapFrame->V86Fs;
TrapFrame->SegGs = TrapFrame->V86Gs;
TrapFrame->SegDs = TrapFrame->V86Ds;
TrapFrame->SegEs = TrapFrame->V86Es;
}
/* Clear direction flag */
@ -402,6 +400,130 @@ KiTrap12Handler(IN PKTRAP_FRAME TrapFrame)
KiSystemFatalException(EXCEPTION_STACK_FAULT, TrapFrame);
}
VOID
FASTCALL
KiTrap14Handler(IN PKTRAP_FRAME TrapFrame)
{
PKTHREAD Thread;
ULONG_PTR Cr2;
NTSTATUS Status;
extern VOID NTAPI ExpInterlockedPopEntrySListFault(VOID);
extern VOID CopyParams(VOID);
extern VOID ReadBatch(VOID);
/* Save trap frame */
KiEnterTrap(TrapFrame);
/* Check for custom VDM trap handler */
if (KeGetPcr()->VdmAlert)
{
/* Not implemented */
UNIMPLEMENTED;
while (TRUE);
}
/* Check if this is the base frame */
Thread = KeGetCurrentThread();
if (KeGetTrapFrame(Thread) != TrapFrame)
{
/* It isn't, check if this is a second nested frame */
if (((ULONG_PTR)KeGetTrapFrame(Thread) - (ULONG_PTR)TrapFrame) <=
FIELD_OFFSET(KTRAP_FRAME, EFlags))
{
/* The stack is somewhere in between frames, we need to fix it */
UNIMPLEMENTED;
while (TRUE);
}
}
/* Save CR2 */
Cr2 = __readcr2();
/* Check for Pentium LOCK errata */
if (KiI386PentiumLockErrataPresent)
{
/* Not yet implemented */
UNIMPLEMENTED;
while (TRUE);
}
/* HACK: Check if interrupts are disabled and enable them */
if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
{
/* Enable interupts */
_enable();
#ifdef HACK_ABOVE_FIXED
if (!(TrapFrame->EFlags & EFLAGS_INTERRUPT_MASK))
{
/* This is illegal */
KeBugCheckWithTf(IRQL_NOT_LESS_OR_EQUAL,
Cr2,
-1,
TrapFrame->ErrCode & 1,
TrapFrame->Eip,
TrapFrame);
}
#endif
}
/* Call the access fault handler */
Status = MmAccessFault(TrapFrame->ErrCode & 1,
(PVOID)Cr2,
TrapFrame->SegCs & MODE_MASK,
TrapFrame);
if (Status == STATUS_SUCCESS) KiEoiHelper(TrapFrame);
/* Check for S-LIST fault */
if (TrapFrame->Eip == (ULONG_PTR)ExpInterlockedPopEntrySListFault)
{
/* Not yet implemented */
UNIMPLEMENTED;
while (TRUE);
}
/* Check for syscall fault */
if ((TrapFrame->Eip == (ULONG_PTR)CopyParams) ||
(TrapFrame->Eip == (ULONG_PTR)ReadBatch))
{
/* Not yet implemented */
UNIMPLEMENTED;
while (TRUE);
}
/* Check for VDM trap */
ASSERT((KiVdmTrap(TrapFrame)) == FALSE);
/* Either kernel or user trap (non VDM) so dispatch exception */
if (Status == STATUS_ACCESS_VIOLATION)
{
/* This status code is repurposed so we can recognize it later */
KiDispatchException2Args(KI_EXCEPTION_ACCESS_VIOLATION,
TrapFrame->Eip,
TrapFrame->ErrCode & 1,
Cr2,
TrapFrame);
}
else if ((Status == STATUS_GUARD_PAGE_VIOLATION) ||
(Status == STATUS_STACK_OVERFLOW))
{
/* These faults only have two parameters */
KiDispatchException2Args(Status,
TrapFrame->Eip,
TrapFrame->ErrCode & 1,
Cr2,
TrapFrame);
}
/* Only other choice is an in-page error, with 3 parameters */
KiDispatchExceptionFromTrapFrame(STATUS_IN_PAGE_ERROR,
TrapFrame->Eip,
3,
TrapFrame->ErrCode & 1,
Cr2,
Status,
TrapFrame);
}
VOID
FASTCALL
KiTrap0FHandler(IN PKTRAP_FRAME TrapFrame)
@ -433,8 +555,8 @@ KiRaiseAssertionHandler(IN PKTRAP_FRAME TrapFrame)
/* Save trap frame */
KiEnterTrap(TrapFrame);
/* Increment EIP to skip the INT2C instruction (2 bytes, not 1 like INT3) */
TrapFrame->Eip += 2;
/* Decrement EIP to point to the INT2C instruction (2 bytes, not 1 like INT3) */
TrapFrame->Eip -= 2;
/* Dispatch the exception */
KiDispatchException0Args(STATUS_ASSERTION_FAILURE,