mirror of
https://github.com/reactos/reactos.git
synced 2024-11-09 08:08:38 +00:00
300 lines
8.2 KiB
C
300 lines
8.2 KiB
C
|
/*
|
||
|
* PROJECT: ReactOS Kernel
|
||
|
* LICENSE: GPL - See COPYING in the top level directory
|
||
|
* FILE: ntoskrnl/ke/amd64/except.c
|
||
|
* PURPOSE: Exception Dispatching for amd64
|
||
|
* PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org)
|
||
|
* Alex Ionescu (alex.ionescu@reactos.org)
|
||
|
*/
|
||
|
|
||
|
/* INCLUDES ******************************************************************/
|
||
|
|
||
|
#include <ntoskrnl.h>
|
||
|
#define NDEBUG
|
||
|
#include <debug.h>
|
||
|
|
||
|
extern ULONG64 InterruptDispatchTable[256];
|
||
|
|
||
|
/* GLOBALS *******************************************************************/
|
||
|
|
||
|
KIDT_INIT KiInterruptInitTable[] =
|
||
|
{
|
||
|
/* Id, Dpl, IST, ServiceRoutine */
|
||
|
{0x00, 0x00, 0x00, KiDivideErrorFault},
|
||
|
{0x01, 0x00, 0x00, KiDebugTrapOrFault},
|
||
|
{0x02, 0x00, 0x03, KiNmiInterrupt},
|
||
|
{0x03, 0x03, 0x00, KiBreakpointTrap},
|
||
|
{0x04, 0x03, 0x00, KiOverflowTrap},
|
||
|
{0x05, 0x00, 0x00, KiBoundFault},
|
||
|
{0x06, 0x00, 0x00, KiInvalidOpcodeFault},
|
||
|
{0x07, 0x00, 0x00, KiNpxNotAvailableFault},
|
||
|
{0x08, 0x00, 0x01, KiDoubleFaultAbort},
|
||
|
{0x09, 0x00, 0x00, KiNpxSegmentOverrunAbort},
|
||
|
{0x0A, 0x00, 0x00, KiInvalidTssFault},
|
||
|
{0x0B, 0x00, 0x00, KiSegmentNotPresentFault},
|
||
|
{0x0C, 0x00, 0x00, KiStackFault},
|
||
|
{0x0D, 0x00, 0x00, KiGeneralProtectionFault},
|
||
|
{0x0E, 0x00, 0x00, KiPageFault},
|
||
|
{0x10, 0x00, 0x00, KiFloatingErrorFault},
|
||
|
{0x11, 0x00, 0x00, KiAlignmentFault},
|
||
|
{0x12, 0x00, 0x02, KiMcheckAbort},
|
||
|
{0x13, 0x00, 0x00, KiXmmException},
|
||
|
{0x1F, 0x00, 0x00, KiApcInterrupt},
|
||
|
{0x2C, 0x03, 0x00, KiRaiseAssertion},
|
||
|
{0x2D, 0x03, 0x00, KiDebugServiceTrap},
|
||
|
{0x2F, 0x00, 0x00, KiDpcInterrupt},
|
||
|
{0xE1, 0x00, 0x00, KiIpiInterrupt},
|
||
|
{0, 0, 0, 0}
|
||
|
};
|
||
|
|
||
|
KIDTENTRY64 KiIdt[256];
|
||
|
KDESCRIPTOR KiIdtDescriptor = {{0}, sizeof(KiIdt) - 1, KiIdt};
|
||
|
|
||
|
|
||
|
/* FUNCTIONS *****************************************************************/
|
||
|
|
||
|
VOID
|
||
|
INIT_FUNCTION
|
||
|
NTAPI
|
||
|
KeInitExceptions(VOID)
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
/* Initialize the Idt */
|
||
|
for (j = i = 0; i < 256; i++)
|
||
|
{
|
||
|
ULONG64 Offset;
|
||
|
|
||
|
if (KiInterruptInitTable[j].InterruptId == i)
|
||
|
{
|
||
|
Offset = (ULONG64)KiInterruptInitTable[j].ServiceRoutine;
|
||
|
KiIdt[i].Dpl = KiInterruptInitTable[j].Dpl;
|
||
|
KiIdt[i].IstIndex = KiInterruptInitTable[j].IstIndex;
|
||
|
j++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Offset = (ULONG64)&InterruptDispatchTable[i];
|
||
|
KiIdt[i].Dpl = 0;
|
||
|
KiIdt[i].IstIndex = 0;
|
||
|
}
|
||
|
KiIdt[i].OffsetLow = Offset & 0xffff;
|
||
|
KiIdt[i].Selector = KGDT64_R0_CODE;
|
||
|
KiIdt[i].Type = 0x0e;
|
||
|
KiIdt[i].Reserved0 = 0;
|
||
|
KiIdt[i].Present = 1;
|
||
|
KiIdt[i].OffsetMiddle = (Offset >> 16) & 0xffff;
|
||
|
KiIdt[i].OffsetHigh = (Offset >> 32);
|
||
|
KiIdt[i].Reserved1 = 0;
|
||
|
}
|
||
|
|
||
|
KeGetPcr()->IdtBase = KiIdt;
|
||
|
__lidt(&KiIdtDescriptor.Limit);
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
NTAPI
|
||
|
KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord,
|
||
|
IN PKEXCEPTION_FRAME ExceptionFrame,
|
||
|
IN PKTRAP_FRAME TrapFrame,
|
||
|
IN KPROCESSOR_MODE PreviousMode,
|
||
|
IN BOOLEAN FirstChance)
|
||
|
{
|
||
|
CONTEXT Context;
|
||
|
|
||
|
// FrLdrDbgPrint("KiDispatchException(%p, %p, %p, %d, %d)\n",
|
||
|
// ExceptionRecord, ExceptionFrame, TrapFrame, PreviousMode, FirstChance);
|
||
|
|
||
|
/* Increase number of Exception Dispatches */
|
||
|
KeGetCurrentPrcb()->KeExceptionDispatchCount++;
|
||
|
|
||
|
/* Set the context flags */
|
||
|
Context.ContextFlags = CONTEXT_ALL;
|
||
|
|
||
|
/* Get a Context */
|
||
|
KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context);
|
||
|
|
||
|
/* Look at our exception code */
|
||
|
switch (ExceptionRecord->ExceptionCode)
|
||
|
{
|
||
|
/* Breakpoint */
|
||
|
case STATUS_BREAKPOINT:
|
||
|
|
||
|
/* Decrement RIP by one */
|
||
|
Context.Rip--;
|
||
|
break;
|
||
|
|
||
|
/* Internal exception */
|
||
|
case KI_EXCEPTION_ACCESS_VIOLATION:
|
||
|
|
||
|
/* Set correct code */
|
||
|
ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION;
|
||
|
if (PreviousMode == UserMode)
|
||
|
{
|
||
|
/* FIXME: Handle no execute */
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Handle kernel-mode first, it's simpler */
|
||
|
if (PreviousMode == KernelMode)
|
||
|
{
|
||
|
/* Check if this is a first-chance exception */
|
||
|
if (FirstChance == TRUE)
|
||
|
{
|
||
|
/* Break into the debugger for the first time */
|
||
|
if (KiDebugRoutine(TrapFrame,
|
||
|
ExceptionFrame,
|
||
|
ExceptionRecord,
|
||
|
&Context,
|
||
|
PreviousMode,
|
||
|
FALSE))
|
||
|
{
|
||
|
/* Exception was handled */
|
||
|
goto Handled;
|
||
|
}
|
||
|
|
||
|
/* If the Debugger couldn't handle it, dispatch the exception */
|
||
|
if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled;
|
||
|
}
|
||
|
|
||
|
/* This is a second-chance exception, only for the debugger */
|
||
|
if (KiDebugRoutine(TrapFrame,
|
||
|
ExceptionFrame,
|
||
|
ExceptionRecord,
|
||
|
&Context,
|
||
|
PreviousMode,
|
||
|
TRUE))
|
||
|
{
|
||
|
/* Exception was handled */
|
||
|
goto Handled;
|
||
|
}
|
||
|
|
||
|
/* Third strike; you're out */
|
||
|
KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED,
|
||
|
ExceptionRecord->ExceptionCode,
|
||
|
(ULONG_PTR)ExceptionRecord->ExceptionAddress,
|
||
|
(ULONG_PTR)TrapFrame,
|
||
|
0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* FIXME: user-mode exception handling unimplemented */
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
|
||
|
Handled:
|
||
|
/* Convert the context back into Trap/Exception Frames */
|
||
|
KeContextToTrapFrame(&Context,
|
||
|
ExceptionFrame,
|
||
|
TrapFrame,
|
||
|
Context.ContextFlags,
|
||
|
PreviousMode);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
NTAPI
|
||
|
KeRaiseUserException(IN NTSTATUS ExceptionCode)
|
||
|
{
|
||
|
UNIMPLEMENTED;
|
||
|
return STATUS_UNSUCCESSFUL;
|
||
|
}
|
||
|
|
||
|
|
||
|
VOID
|
||
|
DECLSPEC_NORETURN
|
||
|
KiSystemFatalException(IN ULONG ExceptionCode,
|
||
|
IN PKTRAP_FRAME TrapFrame)
|
||
|
{
|
||
|
/* Bugcheck the system */
|
||
|
KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP,
|
||
|
ExceptionCode,
|
||
|
0,
|
||
|
0,
|
||
|
0,
|
||
|
TrapFrame);
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
NTAPI
|
||
|
KiNpxNotAvailableFaultHandler(
|
||
|
IN PKTRAP_FRAME TrapFrame)
|
||
|
{
|
||
|
UNIMPLEMENTED;
|
||
|
KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
NTAPI
|
||
|
KiGeneralProtectionFaultHandler(
|
||
|
IN PKTRAP_FRAME TrapFrame)
|
||
|
{
|
||
|
PUCHAR Instructions;
|
||
|
|
||
|
/* Check for user-mode GPF */
|
||
|
if (TrapFrame->SegCs & 3)
|
||
|
{
|
||
|
UNIMPLEMENTED;
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
|
||
|
/* Check for lazy segment load */
|
||
|
if (TrapFrame->SegDs != (KGDT64_R3_DATA | RPL_MASK))
|
||
|
{
|
||
|
/* Fix it */
|
||
|
TrapFrame->SegDs = (KGDT64_R3_DATA | RPL_MASK);
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
else if (TrapFrame->SegEs != (KGDT64_R3_DATA | RPL_MASK))
|
||
|
{
|
||
|
/* Fix it */
|
||
|
TrapFrame->SegEs = (KGDT64_R3_DATA | RPL_MASK);
|
||
|
return STATUS_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/* Check for nested exception */
|
||
|
if ((TrapFrame->Rip >= (ULONG64)KiGeneralProtectionFaultHandler) &&
|
||
|
(TrapFrame->Rip < (ULONG64)KiGeneralProtectionFaultHandler))
|
||
|
{
|
||
|
/* Not implemented */
|
||
|
UNIMPLEMENTED;
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
|
||
|
/* Get Instruction Pointer */
|
||
|
Instructions = (PUCHAR)TrapFrame->Rip;
|
||
|
|
||
|
/* Check for IRET */
|
||
|
if (Instructions[0] == 0x48 && Instructions[1] == 0xCF)
|
||
|
{
|
||
|
/* Not implemented */
|
||
|
UNIMPLEMENTED;
|
||
|
ASSERT(FALSE);
|
||
|
}
|
||
|
|
||
|
/* Check for RDMSR/WRMSR */
|
||
|
if ((Instructions[0] == 0xF) && // 2-byte opcode
|
||
|
(((Instructions[1] >> 8) == 0x30) || // RDMSR
|
||
|
((Instructions[2] >> 8) == 0x32))) // WRMSR
|
||
|
{
|
||
|
/* Unknown CPU MSR, so raise an access violation */
|
||
|
return STATUS_ACCESS_VIOLATION;
|
||
|
}
|
||
|
|
||
|
ASSERT(FALSE);
|
||
|
return STATUS_UNSUCCESSFUL;
|
||
|
}
|
||
|
|
||
|
NTSTATUS
|
||
|
NTAPI
|
||
|
KiXmmExceptionHandler(
|
||
|
IN PKTRAP_FRAME TrapFrame)
|
||
|
{
|
||
|
UNIMPLEMENTED;
|
||
|
KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame);
|
||
|
return -1;
|
||
|
}
|