Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenexcept.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ke/amd64/except.c 00005 * PURPOSE: Exception Dispatching for amd64 00006 * PROGRAMMER: Timo Kreuzer (timo.kreuzer@reactos.org) 00007 * Alex Ionescu (alex.ionescu@reactos.org) 00008 */ 00009 00010 /* INCLUDES ******************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 extern KI_INTERRUPT_DISPATCH_ENTRY KiUnexpectedRange[256]; 00017 00018 /* GLOBALS *******************************************************************/ 00019 00020 KIDT_INIT KiInterruptInitTable[] = 00021 { 00022 /* Id, Dpl, IST, ServiceRoutine */ 00023 {0x00, 0x00, 0x00, KiDivideErrorFault}, 00024 {0x01, 0x00, 0x00, KiDebugTrapOrFault}, 00025 {0x02, 0x00, 0x03, KiNmiInterrupt}, 00026 {0x03, 0x03, 0x00, KiBreakpointTrap}, 00027 {0x04, 0x03, 0x00, KiOverflowTrap}, 00028 {0x05, 0x00, 0x00, KiBoundFault}, 00029 {0x06, 0x00, 0x00, KiInvalidOpcodeFault}, 00030 {0x07, 0x00, 0x00, KiNpxNotAvailableFault}, 00031 {0x08, 0x00, 0x01, KiDoubleFaultAbort}, 00032 {0x09, 0x00, 0x00, KiNpxSegmentOverrunAbort}, 00033 {0x0A, 0x00, 0x00, KiInvalidTssFault}, 00034 {0x0B, 0x00, 0x00, KiSegmentNotPresentFault}, 00035 {0x0C, 0x00, 0x00, KiStackFault}, 00036 {0x0D, 0x00, 0x00, KiGeneralProtectionFault}, 00037 {0x0E, 0x00, 0x00, KiPageFault}, 00038 {0x10, 0x00, 0x00, KiFloatingErrorFault}, 00039 {0x11, 0x00, 0x00, KiAlignmentFault}, 00040 {0x12, 0x00, 0x02, KiMcheckAbort}, 00041 {0x13, 0x00, 0x00, KiXmmException}, 00042 {0x1F, 0x00, 0x00, KiApcInterrupt}, 00043 {0x2C, 0x03, 0x00, KiRaiseAssertion}, 00044 {0x2D, 0x03, 0x00, KiDebugServiceTrap}, 00045 {0x2F, 0x00, 0x00, KiDpcInterrupt}, 00046 {0xE1, 0x00, 0x00, KiIpiInterrupt}, 00047 {0, 0, 0, 0} 00048 }; 00049 00050 KIDTENTRY64 KiIdt[256]; 00051 KDESCRIPTOR KiIdtDescriptor = {{0}, sizeof(KiIdt) - 1, KiIdt}; 00052 00053 00054 /* FUNCTIONS *****************************************************************/ 00055 00056 VOID 00057 INIT_FUNCTION 00058 NTAPI 00059 KeInitExceptions(VOID) 00060 { 00061 int i, j; 00062 00063 /* Initialize the Idt */ 00064 for (j = i = 0; i < 256; i++) 00065 { 00066 ULONG64 Offset; 00067 00068 if (KiInterruptInitTable[j].InterruptId == i) 00069 { 00070 Offset = (ULONG64)KiInterruptInitTable[j].ServiceRoutine; 00071 KiIdt[i].Dpl = KiInterruptInitTable[j].Dpl; 00072 KiIdt[i].IstIndex = KiInterruptInitTable[j].IstIndex; 00073 j++; 00074 } 00075 else 00076 { 00077 Offset = (ULONG64)&KiUnexpectedRange[i]._Op_push; 00078 KiIdt[i].Dpl = 0; 00079 KiIdt[i].IstIndex = 0; 00080 } 00081 KiIdt[i].OffsetLow = Offset & 0xffff; 00082 KiIdt[i].Selector = KGDT64_R0_CODE; 00083 KiIdt[i].Type = 0x0e; 00084 KiIdt[i].Reserved0 = 0; 00085 KiIdt[i].Present = 1; 00086 KiIdt[i].OffsetMiddle = (Offset >> 16) & 0xffff; 00087 KiIdt[i].OffsetHigh = (Offset >> 32); 00088 KiIdt[i].Reserved1 = 0; 00089 } 00090 00091 KeGetPcr()->IdtBase = KiIdt; 00092 __lidt(&KiIdtDescriptor.Limit); 00093 } 00094 00095 static 00096 VOID 00097 KiDispatchExceptionToUser( 00098 IN PKTRAP_FRAME TrapFrame, 00099 IN PCONTEXT Context, 00100 IN PEXCEPTION_RECORD ExceptionRecord) 00101 { 00102 EXCEPTION_RECORD LocalExceptRecord; 00103 ULONG Size; 00104 ULONG64 UserRsp; 00105 PCONTEXT UserContext; 00106 PEXCEPTION_RECORD UserExceptionRecord; 00107 00108 /* Make sure we have a valid SS */ 00109 if (TrapFrame->SegSs != (KGDT64_R3_DATA | RPL_MASK)) 00110 { 00111 /* Raise an access violation instead */ 00112 LocalExceptRecord.ExceptionCode = STATUS_ACCESS_VIOLATION; 00113 LocalExceptRecord.ExceptionFlags = 0; 00114 LocalExceptRecord.NumberParameters = 0; 00115 ExceptionRecord = &LocalExceptRecord; 00116 } 00117 00118 /* Calculate the size of the exception record */ 00119 Size = FIELD_OFFSET(EXCEPTION_RECORD, ExceptionInformation) + 00120 ExceptionRecord->NumberParameters * sizeof(ULONG64); 00121 00122 /* Get new stack pointer and align it to 16 bytes */ 00123 UserRsp = (Context->Rsp - Size - sizeof(CONTEXT)) & ~15; 00124 00125 /* Get pointers to the usermode context and exception record */ 00126 UserContext = (PVOID)UserRsp; 00127 UserExceptionRecord = (PVOID)(UserRsp + sizeof(CONTEXT)); 00128 00129 /* Set up the user-stack */ 00130 _SEH2_TRY 00131 { 00132 /* Probe stack and copy Context */ 00133 ProbeForWrite(UserContext, sizeof(CONTEXT), sizeof(ULONG64)); 00134 *UserContext = *Context; 00135 00136 /* Probe stack and copy exception record */ 00137 ProbeForWrite(UserExceptionRecord, Size, sizeof(ULONG64)); 00138 *UserExceptionRecord = *ExceptionRecord; 00139 } 00140 _SEH2_EXCEPT((LocalExceptRecord = *_SEH2_GetExceptionInformation()->ExceptionRecord), 00141 EXCEPTION_EXECUTE_HANDLER) 00142 { 00143 // FIXNE: handle stack overflow 00144 00145 /* Nothing we can do here */ 00146 _SEH2_YIELD(return); 00147 } 00148 _SEH2_END; 00149 00150 /* Now set the two params for the user-mode dispatcher */ 00151 TrapFrame->Rcx = (ULONG64)UserContext; 00152 TrapFrame->Rdx = (ULONG64)UserExceptionRecord; 00153 00154 /* Set new Stack Pointer */ 00155 TrapFrame->Rsp = UserRsp; 00156 00157 /* Force correct segments */ 00158 TrapFrame->SegCs = KGDT64_R3_CODE | RPL_MASK; 00159 TrapFrame->SegDs = KGDT64_R3_DATA | RPL_MASK; 00160 TrapFrame->SegEs = KGDT64_R3_DATA | RPL_MASK; 00161 TrapFrame->SegFs = KGDT64_R3_CMTEB | RPL_MASK; 00162 TrapFrame->SegGs = KGDT64_R3_DATA | RPL_MASK; 00163 TrapFrame->SegSs = KGDT64_R3_DATA | RPL_MASK; 00164 00165 /* Set RIP to the User-mode Dispatcher */ 00166 TrapFrame->Rip = (ULONG64)KeUserExceptionDispatcher; 00167 00168 /* Exit to usermode */ 00169 KiServiceExit2(TrapFrame); 00170 } 00171 00172 static 00173 VOID 00174 KiPageInDirectory(PVOID ImageBase, USHORT Directory) 00175 { 00176 volatile CHAR *Pointer; 00177 ULONG Size; 00178 00179 /* Get a pointer to the debug directory */ 00180 Pointer = RtlImageDirectoryEntryToData(ImageBase, 1, Directory, &Size); 00181 if (!Pointer) return; 00182 00183 /* Loop all pages */ 00184 while ((LONG)Size > 0) 00185 { 00186 /* Touch it, to page it in */ 00187 (void)*Pointer; 00188 Pointer += PAGE_SIZE; 00189 Size -= PAGE_SIZE; 00190 } 00191 } 00192 00193 VOID 00194 KiPrepareUserDebugData(void) 00195 { 00196 PLDR_DATA_TABLE_ENTRY LdrEntry; 00197 PPEB_LDR_DATA PebLdr; 00198 PLIST_ENTRY ListEntry; 00199 PTEB Teb; 00200 00201 /* Get the Teb for this process */ 00202 Teb = KeGetCurrentThread()->Teb; 00203 if (!Teb) return; 00204 00205 _SEH2_TRY 00206 { 00207 /* Get a pointer to the loader data */ 00208 PebLdr = Teb->ProcessEnvironmentBlock->Ldr; 00209 if (!PebLdr) _SEH2_YIELD(return); 00210 00211 /* Now loop all entries in the module list */ 00212 for (ListEntry = PebLdr->InLoadOrderModuleList.Flink; 00213 ListEntry != &PebLdr->InLoadOrderModuleList; 00214 ListEntry = ListEntry->Flink) 00215 { 00216 /* Get the loader entry */ 00217 LdrEntry = CONTAINING_RECORD(ListEntry, 00218 LDR_DATA_TABLE_ENTRY, 00219 InLoadOrderLinks); 00220 00221 KiPageInDirectory((PVOID)LdrEntry->DllBase, 00222 IMAGE_DIRECTORY_ENTRY_DEBUG); 00223 00224 KiPageInDirectory((PVOID)LdrEntry->DllBase, 00225 IMAGE_DIRECTORY_ENTRY_EXCEPTION); 00226 } 00227 00228 } 00229 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00230 { 00231 } 00232 _SEH2_END 00233 } 00234 00235 VOID 00236 NTAPI 00237 KiDispatchException(IN PEXCEPTION_RECORD ExceptionRecord, 00238 IN PKEXCEPTION_FRAME ExceptionFrame, 00239 IN PKTRAP_FRAME TrapFrame, 00240 IN KPROCESSOR_MODE PreviousMode, 00241 IN BOOLEAN FirstChance) 00242 { 00243 CONTEXT Context; 00244 00245 /* Increase number of Exception Dispatches */ 00246 KeGetCurrentPrcb()->KeExceptionDispatchCount++; 00247 00248 /* Set the context flags */ 00249 Context.ContextFlags = CONTEXT_ALL; 00250 00251 /* Get a Context */ 00252 KeTrapFrameToContext(TrapFrame, ExceptionFrame, &Context); 00253 00254 /* Look at our exception code */ 00255 switch (ExceptionRecord->ExceptionCode) 00256 { 00257 /* Breakpoint */ 00258 case STATUS_BREAKPOINT: 00259 00260 /* Decrement RIP by one */ 00261 Context.Rip--; 00262 break; 00263 00264 /* Internal exception */ 00265 case KI_EXCEPTION_ACCESS_VIOLATION: 00266 00267 /* Set correct code */ 00268 ExceptionRecord->ExceptionCode = STATUS_ACCESS_VIOLATION; 00269 if (PreviousMode == UserMode) 00270 { 00271 /* FIXME: Handle no execute */ 00272 } 00273 break; 00274 } 00275 00276 /* Handle kernel-mode first, it's simpler */ 00277 if (PreviousMode == KernelMode) 00278 { 00279 /* Check if this is a first-chance exception */ 00280 if (FirstChance == TRUE) 00281 { 00282 /* Break into the debugger for the first time */ 00283 if (KiDebugRoutine(TrapFrame, 00284 ExceptionFrame, 00285 ExceptionRecord, 00286 &Context, 00287 PreviousMode, 00288 FALSE)) 00289 { 00290 /* Exception was handled */ 00291 goto Handled; 00292 } 00293 00294 /* If the Debugger couldn't handle it, dispatch the exception */ 00295 if (RtlDispatchException(ExceptionRecord, &Context)) goto Handled; 00296 } 00297 00298 /* This is a second-chance exception, only for the debugger */ 00299 if (KiDebugRoutine(TrapFrame, 00300 ExceptionFrame, 00301 ExceptionRecord, 00302 &Context, 00303 PreviousMode, 00304 TRUE)) 00305 { 00306 /* Exception was handled */ 00307 goto Handled; 00308 } 00309 00310 /* Third strike; you're out */ 00311 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED, 00312 ExceptionRecord->ExceptionCode, 00313 (ULONG_PTR)ExceptionRecord->ExceptionAddress, 00314 (ULONG_PTR)TrapFrame, 00315 0); 00316 } 00317 else 00318 { 00319 /* User mode exception, was it first-chance? */ 00320 if (FirstChance) 00321 { 00322 /* 00323 * Break into the kernel debugger unless a user mode debugger 00324 * is present or user mode exceptions are ignored, except if this 00325 * is a debug service which we must always pass to KD 00326 */ 00327 if ((!(PsGetCurrentProcess()->DebugPort) && 00328 !(KdIgnoreUmExceptions)) || 00329 (KdIsThisAKdTrap(ExceptionRecord, &Context, PreviousMode))) 00330 { 00331 /* Make sure the debugger can access debug directories */ 00332 KiPrepareUserDebugData(); 00333 00334 /* Call the kernel debugger */ 00335 if (KiDebugRoutine(TrapFrame, 00336 ExceptionFrame, 00337 ExceptionRecord, 00338 &Context, 00339 PreviousMode, 00340 FALSE)) 00341 { 00342 /* Exception was handled */ 00343 goto Handled; 00344 } 00345 } 00346 00347 /* Forward exception to user mode debugger */ 00348 if (DbgkForwardException(ExceptionRecord, TRUE, FALSE)) return; 00349 00350 //KiDispatchExceptionToUser() 00351 __debugbreak(); 00352 } 00353 00354 /* Try second chance */ 00355 if (DbgkForwardException(ExceptionRecord, TRUE, TRUE)) 00356 { 00357 /* Handled, get out */ 00358 return; 00359 } 00360 else if (DbgkForwardException(ExceptionRecord, FALSE, TRUE)) 00361 { 00362 /* Handled, get out */ 00363 return; 00364 } 00365 00366 /* 3rd strike, kill the process */ 00367 DPRINT1("Kill %.16s, ExceptionCode: %lx, ExceptionAddress: %lx, BaseAddress: %lx\n", 00368 PsGetCurrentProcess()->ImageFileName, 00369 ExceptionRecord->ExceptionCode, 00370 ExceptionRecord->ExceptionAddress, 00371 PsGetCurrentProcess()->SectionBaseAddress); 00372 00373 ZwTerminateProcess(NtCurrentProcess(), ExceptionRecord->ExceptionCode); 00374 KeBugCheckEx(KMODE_EXCEPTION_NOT_HANDLED, 00375 ExceptionRecord->ExceptionCode, 00376 (ULONG_PTR)ExceptionRecord->ExceptionAddress, 00377 (ULONG_PTR)TrapFrame, 00378 0); 00379 } 00380 00381 Handled: 00382 /* Convert the context back into Trap/Exception Frames */ 00383 KeContextToTrapFrame(&Context, 00384 ExceptionFrame, 00385 TrapFrame, 00386 Context.ContextFlags, 00387 PreviousMode); 00388 return; 00389 } 00390 00391 NTSTATUS 00392 NTAPI 00393 KeRaiseUserException(IN NTSTATUS ExceptionCode) 00394 { 00395 UNIMPLEMENTED; 00396 return STATUS_UNSUCCESSFUL; 00397 } 00398 00399 00400 VOID 00401 DECLSPEC_NORETURN 00402 KiSystemFatalException(IN ULONG ExceptionCode, 00403 IN PKTRAP_FRAME TrapFrame) 00404 { 00405 /* Bugcheck the system */ 00406 KeBugCheckWithTf(UNEXPECTED_KERNEL_MODE_TRAP, 00407 ExceptionCode, 00408 0, 00409 0, 00410 0, 00411 TrapFrame); 00412 } 00413 00414 NTSTATUS 00415 NTAPI 00416 KiNpxNotAvailableFaultHandler( 00417 IN PKTRAP_FRAME TrapFrame) 00418 { 00419 UNIMPLEMENTED; 00420 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame); 00421 return -1; 00422 } 00423 00424 00425 NTSTATUS 00426 NTAPI 00427 KiGeneralProtectionFaultHandler( 00428 IN PKTRAP_FRAME TrapFrame) 00429 { 00430 PUCHAR Instructions; 00431 00432 /* Check for user-mode GPF */ 00433 if (TrapFrame->SegCs & 3) 00434 { 00435 UNIMPLEMENTED; 00436 ASSERT(FALSE); 00437 } 00438 00439 /* Check for lazy segment load */ 00440 if (TrapFrame->SegDs != (KGDT64_R3_DATA | RPL_MASK)) 00441 { 00442 /* Fix it */ 00443 TrapFrame->SegDs = (KGDT64_R3_DATA | RPL_MASK); 00444 return STATUS_SUCCESS; 00445 } 00446 else if (TrapFrame->SegEs != (KGDT64_R3_DATA | RPL_MASK)) 00447 { 00448 /* Fix it */ 00449 TrapFrame->SegEs = (KGDT64_R3_DATA | RPL_MASK); 00450 return STATUS_SUCCESS; 00451 } 00452 00453 /* Check for nested exception */ 00454 if ((TrapFrame->Rip >= (ULONG64)KiGeneralProtectionFaultHandler) && 00455 (TrapFrame->Rip < (ULONG64)KiGeneralProtectionFaultHandler)) 00456 { 00457 /* Not implemented */ 00458 UNIMPLEMENTED; 00459 ASSERT(FALSE); 00460 } 00461 00462 /* Get Instruction Pointer */ 00463 Instructions = (PUCHAR)TrapFrame->Rip; 00464 00465 /* Check for IRET */ 00466 if (Instructions[0] == 0x48 && Instructions[1] == 0xCF) 00467 { 00468 /* Not implemented */ 00469 UNIMPLEMENTED; 00470 ASSERT(FALSE); 00471 } 00472 00473 /* Check for RDMSR/WRMSR */ 00474 if ((Instructions[0] == 0xF) && // 2-byte opcode 00475 ((Instructions[1] == 0x30) || // RDMSR 00476 (Instructions[1] == 0x32))) // WRMSR 00477 { 00478 /* Unknown CPU MSR, so raise an access violation */ 00479 return STATUS_ACCESS_VIOLATION; 00480 } 00481 00482 ASSERT(FALSE); 00483 return STATUS_UNSUCCESSFUL; 00484 } 00485 00486 NTSTATUS 00487 NTAPI 00488 KiXmmExceptionHandler( 00489 IN PKTRAP_FRAME TrapFrame) 00490 { 00491 UNIMPLEMENTED; 00492 KeBugCheckWithTf(TRAP_CAUSE_UNKNOWN, 13, 0, 0, 1, TrapFrame); 00493 return -1; 00494 } Generated on Sat May 26 2012 04:22:57 for ReactOS by
1.7.6.1
|