/* * 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 #define NDEBUG #include 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; }