mirror of
https://github.com/reactos/reactos.git
synced 2025-02-24 01:15:09 +00:00
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:
parent
b308ece644
commit
8323208ddf
3 changed files with 157 additions and 215 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue