1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/ke/bug.c 5 * PURPOSE: Bugcheck Support 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 13 #ifdef KDBG 14 #include <kdbg/kdb.h> 15 #endif 16 17 #define NDEBUG 18 #include <debug.h> 19 20 /* GLOBALS *******************************************************************/ 21 22 LIST_ENTRY KeBugcheckCallbackListHead; 23 LIST_ENTRY KeBugcheckReasonCallbackListHead; 24 KSPIN_LOCK BugCheckCallbackLock; 25 ULONG KeBugCheckActive, KeBugCheckOwner; 26 LONG KeBugCheckOwnerRecursionCount; 27 PMESSAGE_RESOURCE_DATA KiBugCodeMessages; 28 ULONG KeBugCheckCount = 1; 29 ULONG KiHardwareTrigger; 30 PUNICODE_STRING KiBugCheckDriver; 31 ULONG_PTR KiBugCheckData[5]; 32 33 PKNMI_HANDLER_CALLBACK KiNmiCallbackListHead = NULL; 34 KSPIN_LOCK KiNmiCallbackListLock; 35 36 /* Jira Reporting */ 37 UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion; 38 UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion; 39 40 /* PRIVATE FUNCTIONS *********************************************************/ 41 42 PVOID 43 NTAPI 44 KiPcToFileHeader(IN PVOID Pc, 45 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry, 46 IN BOOLEAN DriversOnly, 47 OUT PBOOLEAN InKernel) 48 { 49 ULONG i = 0; 50 PVOID ImageBase, PcBase = NULL; 51 PLDR_DATA_TABLE_ENTRY Entry; 52 PLIST_ENTRY ListHead, NextEntry; 53 54 /* Check which list we should use */ 55 ListHead = (KeLoaderBlock) ? &KeLoaderBlock->LoadOrderListHead : 56 &PsLoadedModuleList; 57 58 /* Assume no */ 59 *InKernel = FALSE; 60 61 /* Set list pointers and make sure it's valid */ 62 NextEntry = ListHead->Flink; 63 if (NextEntry) 64 { 65 /* Start loop */ 66 while (NextEntry != ListHead) 67 { 68 /* Increase entry */ 69 i++; 70 71 /* Check if this is a kernel entry and we only want drivers */ 72 if ((i <= 2) && (DriversOnly != FALSE)) 73 { 74 /* Skip it */ 75 NextEntry = NextEntry->Flink; 76 continue; 77 } 78 79 /* Get the loader entry */ 80 Entry = CONTAINING_RECORD(NextEntry, 81 LDR_DATA_TABLE_ENTRY, 82 InLoadOrderLinks); 83 84 /* Move to the next entry */ 85 NextEntry = NextEntry->Flink; 86 ImageBase = Entry->DllBase; 87 88 /* Check if this is the right one */ 89 if (((ULONG_PTR)Pc >= (ULONG_PTR)Entry->DllBase) && 90 ((ULONG_PTR)Pc < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage))) 91 { 92 /* Return this entry */ 93 *LdrEntry = Entry; 94 PcBase = ImageBase; 95 96 /* Check if this was a kernel or HAL entry */ 97 if (i <= 2) *InKernel = TRUE; 98 break; 99 } 100 } 101 } 102 103 /* Return the base address */ 104 return PcBase; 105 } 106 107 PVOID 108 NTAPI 109 KiRosPcToUserFileHeader(IN PVOID Pc, 110 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry) 111 { 112 PVOID ImageBase, PcBase = NULL; 113 PLDR_DATA_TABLE_ENTRY Entry; 114 PLIST_ENTRY ListHead, NextEntry; 115 116 /* 117 * We know this is valid because we should only be called after a 118 * succesfull address from RtlWalkFrameChain for UserMode, which 119 * validates everything for us. 120 */ 121 ListHead = &KeGetCurrentThread()-> 122 Teb->ProcessEnvironmentBlock->Ldr->InLoadOrderModuleList; 123 124 /* Set list pointers and make sure it's valid */ 125 NextEntry = ListHead->Flink; 126 if (NextEntry) 127 { 128 /* Start loop */ 129 while (NextEntry != ListHead) 130 { 131 /* Get the loader entry */ 132 Entry = CONTAINING_RECORD(NextEntry, 133 LDR_DATA_TABLE_ENTRY, 134 InLoadOrderLinks); 135 136 /* Move to the next entry */ 137 NextEntry = NextEntry->Flink; 138 ImageBase = Entry->DllBase; 139 140 /* Check if this is the right one */ 141 if (((ULONG_PTR)Pc >= (ULONG_PTR)Entry->DllBase) && 142 ((ULONG_PTR)Pc < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage))) 143 { 144 /* Return this entry */ 145 *LdrEntry = Entry; 146 PcBase = ImageBase; 147 break; 148 } 149 } 150 } 151 152 /* Return the base address */ 153 return PcBase; 154 } 155 156 USHORT 157 NTAPI 158 KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip, 159 IN ULONG FramesToCapture, 160 OUT PVOID *BackTrace, 161 OUT PULONG BackTraceHash OPTIONAL) 162 { 163 PVOID Frames[2 * 64]; 164 ULONG FrameCount; 165 ULONG Hash = 0, i; 166 167 /* Skip a frame for the caller */ 168 FramesToSkip++; 169 170 /* Don't go past the limit */ 171 if ((FramesToCapture + FramesToSkip) >= 128) return 0; 172 173 /* Do the back trace */ 174 FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 1); 175 176 /* Make sure we're not skipping all of them */ 177 if (FrameCount <= FramesToSkip) return 0; 178 179 /* Loop all the frames */ 180 for (i = 0; i < FramesToCapture; i++) 181 { 182 /* Don't go past the limit */ 183 if ((FramesToSkip + i) >= FrameCount) break; 184 185 /* Save this entry and hash it */ 186 BackTrace[i] = Frames[FramesToSkip + i]; 187 Hash += PtrToUlong(BackTrace[i]); 188 } 189 190 /* Write the hash */ 191 if (BackTraceHash) *BackTraceHash = Hash; 192 193 /* Clear the other entries and return count */ 194 RtlFillMemoryUlong(Frames, 128, 0); 195 return (USHORT)i; 196 } 197 198 199 VOID 200 FASTCALL 201 KeRosDumpStackFrameArray(IN PULONG_PTR Frames, 202 IN ULONG FrameCount) 203 { 204 ULONG i; 205 ULONG_PTR Addr; 206 BOOLEAN InSystem; 207 PVOID p; 208 209 /* GCC complaints that it may be used uninitialized */ 210 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL; 211 212 /* Loop them */ 213 for (i = 0; i < FrameCount; i++) 214 { 215 /* Get the EIP */ 216 Addr = Frames[i]; 217 if (!Addr) 218 { 219 break; 220 } 221 222 /* Get the base for this file */ 223 if (Addr > (ULONG_PTR)MmHighestUserAddress) 224 { 225 /* We are in kernel */ 226 p = KiPcToFileHeader((PVOID)Addr, &LdrEntry, FALSE, &InSystem); 227 } 228 else 229 { 230 /* We are in user land */ 231 p = KiRosPcToUserFileHeader((PVOID)Addr, &LdrEntry); 232 } 233 if (p) 234 { 235 #ifdef KDBG 236 if (!KdbSymPrintAddress((PVOID)Addr, NULL)) 237 #endif 238 { 239 CHAR AnsiName[64]; 240 241 /* Convert module name to ANSI and print it */ 242 KeBugCheckUnicodeToAnsi(&LdrEntry->BaseDllName, 243 AnsiName, 244 sizeof(AnsiName)); 245 Addr -= (ULONG_PTR)LdrEntry->DllBase; 246 DbgPrint("<%s: %p>", AnsiName, (PVOID)Addr); 247 } 248 } 249 else 250 { 251 /* Print only the address */ 252 DbgPrint("<%p>", (PVOID)Addr); 253 } 254 255 /* Go to the next frame */ 256 DbgPrint("\n"); 257 } 258 } 259 260 VOID 261 NTAPI 262 KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL, 263 IN ULONG FrameCount OPTIONAL) 264 { 265 ULONG_PTR Frames[32]; 266 ULONG RealFrameCount; 267 268 /* If the caller didn't ask, assume 32 frames */ 269 if (!FrameCount || FrameCount > 32) FrameCount = 32; 270 271 if (Frame) 272 { 273 /* Dump them */ 274 KeRosDumpStackFrameArray(Frame, FrameCount); 275 } 276 else 277 { 278 /* Get the current frames (skip the two. One for the dumper, one for the caller) */ 279 RealFrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL); 280 DPRINT1("RealFrameCount =%lu\n", RealFrameCount); 281 282 /* Dump them */ 283 KeRosDumpStackFrameArray(Frames, RealFrameCount); 284 285 /* Count left for user mode? */ 286 if (FrameCount - RealFrameCount > 0) 287 { 288 /* Get the current frames */ 289 RealFrameCount = KeRosCaptureUserStackBackTrace(-1, FrameCount - RealFrameCount, (PVOID*)Frames, NULL); 290 291 /* Dump them */ 292 KeRosDumpStackFrameArray(Frames, RealFrameCount); 293 } 294 } 295 } 296 297 CODE_SEG("INIT") 298 VOID 299 NTAPI 300 KiInitializeBugCheck(VOID) 301 { 302 PMESSAGE_RESOURCE_DATA BugCheckData; 303 LDR_RESOURCE_INFO ResourceInfo; 304 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry; 305 NTSTATUS Status; 306 PLDR_DATA_TABLE_ENTRY LdrEntry; 307 308 /* Get the kernel entry */ 309 LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink, 310 LDR_DATA_TABLE_ENTRY, 311 InLoadOrderLinks); 312 313 /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */ 314 ResourceInfo.Type = 11; 315 ResourceInfo.Name = 1; 316 ResourceInfo.Language = 9; 317 318 /* Do the lookup. */ 319 Status = LdrFindResource_U(LdrEntry->DllBase, 320 &ResourceInfo, 321 RESOURCE_DATA_LEVEL, 322 &ResourceDataEntry); 323 324 /* Make sure it worked */ 325 if (NT_SUCCESS(Status)) 326 { 327 /* Now actually get a pointer to it */ 328 Status = LdrAccessResource(LdrEntry->DllBase, 329 ResourceDataEntry, 330 (PVOID*)&BugCheckData, 331 NULL); 332 if (NT_SUCCESS(Status)) KiBugCodeMessages = BugCheckData; 333 } 334 } 335 336 BOOLEAN 337 NTAPI 338 KeGetBugMessageText(IN ULONG BugCheckCode, 339 OUT PANSI_STRING OutputString OPTIONAL) 340 { 341 ULONG i; 342 ULONG IdOffset; 343 PMESSAGE_RESOURCE_ENTRY MessageEntry; 344 PCHAR BugCode; 345 USHORT Length; 346 BOOLEAN Result = FALSE; 347 348 /* Make sure we're not bugchecking too early */ 349 if (!KiBugCodeMessages) return Result; 350 351 /* 352 * Globally protect in SEH as we are trying to access data in 353 * dire situations, and potentially going to patch it (see below). 354 */ 355 _SEH2_TRY 356 { 357 358 /* 359 * Make the kernel resource section writable, as we are going to manually 360 * trim the trailing newlines in the bugcheck resource message in place, 361 * when OutputString is NULL and before displaying it on screen. 362 */ 363 MmMakeKernelResourceSectionWritable(); 364 365 /* Find the message. This code is based on RtlFindMesssage */ 366 for (i = 0; i < KiBugCodeMessages->NumberOfBlocks; i++) 367 { 368 /* Check if the ID matches */ 369 if ((BugCheckCode >= KiBugCodeMessages->Blocks[i].LowId) && 370 (BugCheckCode <= KiBugCodeMessages->Blocks[i].HighId)) 371 { 372 /* Get offset to entry */ 373 MessageEntry = (PMESSAGE_RESOURCE_ENTRY) 374 ((ULONG_PTR)KiBugCodeMessages + KiBugCodeMessages->Blocks[i].OffsetToEntries); 375 IdOffset = BugCheckCode - KiBugCodeMessages->Blocks[i].LowId; 376 377 /* Advance in the entries until finding it */ 378 while (IdOffset--) 379 { 380 MessageEntry = (PMESSAGE_RESOURCE_ENTRY) 381 ((ULONG_PTR)MessageEntry + MessageEntry->Length); 382 } 383 384 /* Make sure it's not Unicode */ 385 ASSERT(!(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE)); 386 387 /* Get the final code */ 388 BugCode = (PCHAR)MessageEntry->Text; 389 Length = (USHORT)strlen(BugCode); 390 391 /* Handle trailing newlines */ 392 while ((Length > 0) && ((BugCode[Length - 1] == '\n') || 393 (BugCode[Length - 1] == '\r') || 394 (BugCode[Length - 1] == ANSI_NULL))) 395 { 396 /* Directly trim the newline in place if we don't return the string */ 397 if (!OutputString) BugCode[Length - 1] = ANSI_NULL; 398 399 /* Skip the trailing newline */ 400 Length--; 401 } 402 403 /* Check if caller wants an output string */ 404 if (OutputString) 405 { 406 /* Return it in the OutputString */ 407 OutputString->Buffer = BugCode; 408 OutputString->Length = Length; 409 OutputString->MaximumLength = Length; 410 } 411 else 412 { 413 /* Direct output to screen */ 414 InbvDisplayString(BugCode); 415 InbvDisplayString("\r"); 416 } 417 418 /* We're done */ 419 Result = TRUE; 420 break; 421 } 422 } 423 424 } 425 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 426 { 427 } 428 _SEH2_END; 429 430 /* Return the result */ 431 return Result; 432 } 433 434 VOID 435 NTAPI 436 KiDoBugCheckCallbacks(VOID) 437 { 438 PKBUGCHECK_CALLBACK_RECORD CurrentRecord; 439 PLIST_ENTRY ListHead, NextEntry, LastEntry; 440 ULONG_PTR Checksum; 441 442 /* First make sure that the list is initialized... it might not be */ 443 ListHead = &KeBugcheckCallbackListHead; 444 if ((!ListHead->Flink) || (!ListHead->Blink)) 445 return; 446 447 /* Loop the list */ 448 LastEntry = ListHead; 449 NextEntry = ListHead->Flink; 450 while (NextEntry != ListHead) 451 { 452 /* Get the reord */ 453 CurrentRecord = CONTAINING_RECORD(NextEntry, 454 KBUGCHECK_CALLBACK_RECORD, 455 Entry); 456 457 /* Validate it */ 458 // TODO/FIXME: Check whether the memory CurrentRecord points to 459 // is still accessible and valid! 460 if (CurrentRecord->Entry.Blink != LastEntry) return; 461 Checksum = (ULONG_PTR)CurrentRecord->CallbackRoutine; 462 Checksum += (ULONG_PTR)CurrentRecord->Buffer; 463 Checksum += (ULONG_PTR)CurrentRecord->Length; 464 Checksum += (ULONG_PTR)CurrentRecord->Component; 465 466 /* Make sure it's inserted and validated */ 467 if ((CurrentRecord->State == BufferInserted) && 468 (CurrentRecord->Checksum == Checksum)) 469 { 470 /* Call the routine */ 471 CurrentRecord->State = BufferStarted; 472 _SEH2_TRY 473 { 474 (CurrentRecord->CallbackRoutine)(CurrentRecord->Buffer, 475 CurrentRecord->Length); 476 CurrentRecord->State = BufferFinished; 477 } 478 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 479 { 480 CurrentRecord->State = BufferIncomplete; 481 } 482 _SEH2_END; 483 } 484 485 /* Go to the next entry */ 486 LastEntry = NextEntry; 487 NextEntry = NextEntry->Flink; 488 } 489 } 490 491 VOID 492 NTAPI 493 KiBugCheckDebugBreak(IN ULONG StatusCode) 494 { 495 /* 496 * Wrap this in SEH so we don't crash if 497 * there is no debugger or if it disconnected 498 */ 499 DoBreak: 500 _SEH2_TRY 501 { 502 /* Breakpoint */ 503 DbgBreakPointWithStatus(StatusCode); 504 } 505 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 506 { 507 /* No debugger, halt the CPU */ 508 HalHaltSystem(); 509 } 510 _SEH2_END; 511 512 /* Break again if this wasn't first try */ 513 if (StatusCode != DBG_STATUS_BUGCHECK_FIRST) goto DoBreak; 514 } 515 516 PCHAR 517 NTAPI 518 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode, 519 OUT PCHAR Ansi, 520 IN ULONG Length) 521 { 522 PCHAR p; 523 PWCHAR pw; 524 ULONG i; 525 526 /* Set length and normalize it */ 527 i = Unicode->Length / sizeof(WCHAR); 528 i = min(i, Length - 1); 529 530 /* Set source and destination, and copy */ 531 pw = Unicode->Buffer; 532 p = Ansi; 533 while (i--) *p++ = (CHAR)*pw++; 534 535 /* Null terminate and return */ 536 *p = ANSI_NULL; 537 return Ansi; 538 } 539 540 VOID 541 NTAPI 542 KiDumpParameterImages(IN PCHAR Message, 543 IN PULONG_PTR Parameters, 544 IN ULONG ParameterCount, 545 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine) 546 { 547 ULONG i; 548 BOOLEAN InSystem; 549 PLDR_DATA_TABLE_ENTRY LdrEntry; 550 PVOID ImageBase; 551 PUNICODE_STRING DriverName; 552 CHAR AnsiName[32]; 553 PIMAGE_NT_HEADERS NtHeader; 554 ULONG TimeStamp; 555 BOOLEAN FirstRun = TRUE; 556 557 /* Loop parameters */ 558 for (i = 0; i < ParameterCount; i++) 559 { 560 /* Get the base for this parameter */ 561 ImageBase = KiPcToFileHeader((PVOID)Parameters[i], 562 &LdrEntry, 563 FALSE, 564 &InSystem); 565 if (!ImageBase) 566 { 567 /* FIXME: Add code to check for unloaded drivers */ 568 DPRINT1("Potentially unloaded driver!\n"); 569 continue; 570 } 571 else 572 { 573 /* Get the NT Headers and Timestamp */ 574 NtHeader = RtlImageNtHeader(LdrEntry->DllBase); 575 TimeStamp = NtHeader->FileHeader.TimeDateStamp; 576 577 /* Convert the driver name */ 578 DriverName = &LdrEntry->BaseDllName; 579 ConversionRoutine(&LdrEntry->BaseDllName, 580 AnsiName, 581 sizeof(AnsiName)); 582 } 583 584 /* Format driver name */ 585 sprintf(Message, 586 "%s** %12s - Address %p base at %p, DateStamp %08lx\r\n", 587 FirstRun ? "\r\n*":"*", 588 AnsiName, 589 (PVOID)Parameters[i], 590 ImageBase, 591 TimeStamp); 592 593 /* Check if we only had one parameter */ 594 if (ParameterCount <= 1) 595 { 596 /* Then just save the name */ 597 KiBugCheckDriver = DriverName; 598 } 599 else 600 { 601 /* Otherwise, display the message */ 602 InbvDisplayString(Message); 603 } 604 605 /* Loop again */ 606 FirstRun = FALSE; 607 } 608 } 609 610 VOID 611 NTAPI 612 KiDisplayBlueScreen(IN ULONG MessageId, 613 IN BOOLEAN IsHardError, 614 IN PCHAR HardErrCaption OPTIONAL, 615 IN PCHAR HardErrMessage OPTIONAL, 616 IN PCHAR Message) 617 { 618 ULONG BugCheckCode = (ULONG)KiBugCheckData[0]; 619 BOOLEAN Enable = TRUE; 620 CHAR AnsiName[107]; 621 622 /* Enable headless support for bugcheck */ 623 HeadlessDispatch(HeadlessCmdStartBugCheck, 624 NULL, 0, NULL, NULL); 625 HeadlessDispatch(HeadlessCmdEnableTerminal, 626 &Enable, sizeof(Enable), 627 NULL, NULL); 628 HeadlessDispatch(HeadlessCmdSendBlueScreenData, 629 &BugCheckCode, sizeof(BugCheckCode), 630 NULL, NULL); 631 632 /* Check if bootvid is installed */ 633 if (InbvIsBootDriverInstalled()) 634 { 635 /* Acquire ownership and reset the display */ 636 InbvAcquireDisplayOwnership(); 637 InbvResetDisplay(); 638 639 /* Display blue screen */ 640 InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLUE); 641 InbvSetTextColor(BV_COLOR_WHITE); 642 InbvInstallDisplayStringFilter(NULL); 643 InbvEnableDisplayString(TRUE); 644 InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1); 645 } 646 647 /* Check if this is a hard error */ 648 if (IsHardError) 649 { 650 /* Display caption and message */ 651 if (HardErrCaption) InbvDisplayString(HardErrCaption); 652 if (HardErrMessage) InbvDisplayString(HardErrMessage); 653 } 654 655 /* Begin the display */ 656 InbvDisplayString("\r\n"); 657 658 /* Print out initial message */ 659 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL); 660 InbvDisplayString("\r\n\r\n"); 661 662 /* Check if we have a driver */ 663 if (KiBugCheckDriver) 664 { 665 /* Print out into to driver name */ 666 KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL); 667 668 /* Convert and print out driver name */ 669 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName)); 670 InbvDisplayString(" "); 671 InbvDisplayString(AnsiName); 672 InbvDisplayString("\r\n\r\n"); 673 } 674 675 /* Check if this is the generic message */ 676 if (MessageId == BUGCODE_PSS_MESSAGE) 677 { 678 /* It is, so get the bug code string as well */ 679 KeGetBugMessageText(BugCheckCode, NULL); 680 InbvDisplayString("\r\n\r\n"); 681 } 682 683 /* Print second introduction message */ 684 KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL); 685 InbvDisplayString("\r\n\r\n"); 686 687 /* Get the bug code string */ 688 KeGetBugMessageText(MessageId, NULL); 689 InbvDisplayString("\r\n\r\n"); 690 691 /* Print message for technical information */ 692 KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL); 693 694 /* Show the technical Data */ 695 RtlStringCbPrintfA(AnsiName, 696 sizeof(AnsiName), 697 "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n", 698 BugCheckCode, 699 (PVOID)KiBugCheckData[1], 700 (PVOID)KiBugCheckData[2], 701 (PVOID)KiBugCheckData[3], 702 (PVOID)KiBugCheckData[4]); 703 InbvDisplayString(AnsiName); 704 705 /* Check if we have a driver*/ 706 if (KiBugCheckDriver) 707 { 708 /* Display technical driver data */ 709 InbvDisplayString(Message); 710 } 711 else 712 { 713 /* Dump parameter information */ 714 KiDumpParameterImages(Message, 715 (PVOID)&KiBugCheckData[1], 716 4, 717 KeBugCheckUnicodeToAnsi); 718 } 719 } 720 721 DECLSPEC_NORETURN 722 VOID 723 NTAPI 724 KeBugCheckWithTf(IN ULONG BugCheckCode, 725 IN ULONG_PTR BugCheckParameter1, 726 IN ULONG_PTR BugCheckParameter2, 727 IN ULONG_PTR BugCheckParameter3, 728 IN ULONG_PTR BugCheckParameter4, 729 IN PKTRAP_FRAME TrapFrame) 730 { 731 PKPRCB Prcb = KeGetCurrentPrcb(); 732 CONTEXT Context; 733 ULONG MessageId; 734 CHAR AnsiName[128]; 735 BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE; 736 PCHAR HardErrCaption = NULL, HardErrMessage = NULL; 737 PVOID Pc = NULL, Memory; 738 PVOID DriverBase; 739 PLDR_DATA_TABLE_ENTRY LdrEntry; 740 PULONG_PTR HardErrorParameters; 741 KIRQL OldIrql; 742 743 /* Set active bugcheck */ 744 KeBugCheckActive = TRUE; 745 KiBugCheckDriver = NULL; 746 747 /* Check if this is power failure simulation */ 748 if (BugCheckCode == POWER_FAILURE_SIMULATE) 749 { 750 /* Call the Callbacks and reboot */ 751 KiDoBugCheckCallbacks(); 752 HalReturnToFirmware(HalRebootRoutine); 753 } 754 755 /* Save the IRQL and set hardware trigger */ 756 Prcb->DebuggerSavedIRQL = KeGetCurrentIrql(); 757 InterlockedIncrement((PLONG)&KiHardwareTrigger); 758 759 /* Capture the CPU Context */ 760 RtlCaptureContext(&Prcb->ProcessorState.ContextFrame); 761 KiSaveProcessorControlState(&Prcb->ProcessorState); 762 Context = Prcb->ProcessorState.ContextFrame; 763 764 /* FIXME: Call the Watchdog if it's registered */ 765 766 /* Check which bugcode this is */ 767 switch (BugCheckCode) 768 { 769 /* These bug checks already have detailed messages, keep them */ 770 case UNEXPECTED_KERNEL_MODE_TRAP: 771 case DRIVER_CORRUPTED_EXPOOL: 772 case ACPI_BIOS_ERROR: 773 case ACPI_BIOS_FATAL_ERROR: 774 case THREAD_STUCK_IN_DEVICE_DRIVER: 775 case DATA_BUS_ERROR: 776 case FAT_FILE_SYSTEM: 777 case NO_MORE_SYSTEM_PTES: 778 case INACCESSIBLE_BOOT_DEVICE: 779 780 /* Keep the same code */ 781 MessageId = BugCheckCode; 782 break; 783 784 /* Check if this is a kernel-mode exception */ 785 case KERNEL_MODE_EXCEPTION_NOT_HANDLED: 786 case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED: 787 case KMODE_EXCEPTION_NOT_HANDLED: 788 789 /* Use the generic text message */ 790 MessageId = KMODE_EXCEPTION_NOT_HANDLED; 791 break; 792 793 /* File-system errors */ 794 case NTFS_FILE_SYSTEM: 795 796 /* Use the generic message for FAT */ 797 MessageId = FAT_FILE_SYSTEM; 798 break; 799 800 /* Check if this is a coruption of the Mm's Pool */ 801 case DRIVER_CORRUPTED_MMPOOL: 802 803 /* Use generic corruption message */ 804 MessageId = DRIVER_CORRUPTED_EXPOOL; 805 break; 806 807 /* Check if this is a signature check failure */ 808 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE: 809 810 /* Use the generic corruption message */ 811 MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE; 812 break; 813 814 /* All other codes */ 815 default: 816 817 /* Use the default bugcheck message */ 818 MessageId = BUGCODE_PSS_MESSAGE; 819 break; 820 } 821 822 /* Save bugcheck data */ 823 KiBugCheckData[0] = BugCheckCode; 824 KiBugCheckData[1] = BugCheckParameter1; 825 KiBugCheckData[2] = BugCheckParameter2; 826 KiBugCheckData[3] = BugCheckParameter3; 827 KiBugCheckData[4] = BugCheckParameter4; 828 829 /* Now check what bugcheck this is */ 830 switch (BugCheckCode) 831 { 832 /* Invalid access to R/O memory or Unhandled KM Exception */ 833 case KERNEL_MODE_EXCEPTION_NOT_HANDLED: 834 case ATTEMPTED_WRITE_TO_READONLY_MEMORY: 835 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY: 836 { 837 /* Check if we have a trap frame */ 838 if (!TrapFrame) 839 { 840 /* Use parameter 3 as a trap frame, if it exists */ 841 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3; 842 } 843 844 /* Check if we got one now and if we need to get the Program Counter */ 845 if ((TrapFrame) && 846 (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED)) 847 { 848 /* Get the Program Counter */ 849 Pc = (PVOID)KeGetTrapFramePc(TrapFrame); 850 } 851 break; 852 } 853 854 /* Wrong IRQL */ 855 case IRQL_NOT_LESS_OR_EQUAL: 856 { 857 /* 858 * The NT kernel has 3 special sections: 859 * MISYSPTE, POOLMI and POOLCODE. The bug check code can 860 * determine in which of these sections this bugcode happened 861 * and provide a more detailed analysis. For now, we don't. 862 */ 863 864 /* Program Counter is in parameter 4 */ 865 Pc = (PVOID)BugCheckParameter4; 866 867 /* Get the driver base */ 868 DriverBase = KiPcToFileHeader(Pc, 869 &LdrEntry, 870 FALSE, 871 &IsSystem); 872 if (IsSystem) 873 { 874 /* 875 * The error happened inside the kernel or HAL. 876 * Get the memory address that was being referenced. 877 */ 878 Memory = (PVOID)BugCheckParameter1; 879 880 /* Find to which driver it belongs */ 881 DriverBase = KiPcToFileHeader(Memory, 882 &LdrEntry, 883 TRUE, 884 &IsSystem); 885 if (DriverBase) 886 { 887 /* Get the driver name and update the bug code */ 888 KiBugCheckDriver = &LdrEntry->BaseDllName; 889 KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED; 890 } 891 else 892 { 893 /* Find the driver that unloaded at this address */ 894 KiBugCheckDriver = NULL; // FIXME: ROS can't locate 895 896 /* Check if the cause was an unloaded driver */ 897 if (KiBugCheckDriver) 898 { 899 /* Update bug check code */ 900 KiBugCheckData[0] = 901 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD; 902 } 903 } 904 } 905 else 906 { 907 /* Update the bug check code */ 908 KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL; 909 } 910 911 /* Clear Pc so we don't look it up later */ 912 Pc = NULL; 913 break; 914 } 915 916 /* Hard error */ 917 case FATAL_UNHANDLED_HARD_ERROR: 918 { 919 /* Copy bug check data from hard error */ 920 HardErrorParameters = (PULONG_PTR)BugCheckParameter2; 921 KiBugCheckData[0] = BugCheckParameter1; 922 KiBugCheckData[1] = HardErrorParameters[0]; 923 KiBugCheckData[2] = HardErrorParameters[1]; 924 KiBugCheckData[3] = HardErrorParameters[2]; 925 KiBugCheckData[4] = HardErrorParameters[3]; 926 927 /* Remember that this is hard error and set the caption/message */ 928 IsHardError = TRUE; 929 HardErrCaption = (PCHAR)BugCheckParameter3; 930 HardErrMessage = (PCHAR)BugCheckParameter4; 931 break; 932 } 933 934 /* Page fault */ 935 case PAGE_FAULT_IN_NONPAGED_AREA: 936 { 937 /* Assume no driver */ 938 DriverBase = NULL; 939 940 /* Check if we have a trap frame */ 941 if (!TrapFrame) 942 { 943 /* We don't, use parameter 3 if possible */ 944 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3; 945 } 946 947 /* Check if we have a frame now */ 948 if (TrapFrame) 949 { 950 /* Get the Program Counter */ 951 Pc = (PVOID)KeGetTrapFramePc(TrapFrame); 952 KiBugCheckData[3] = (ULONG_PTR)Pc; 953 954 /* Find out if was in the kernel or drivers */ 955 DriverBase = KiPcToFileHeader(Pc, 956 &LdrEntry, 957 FALSE, 958 &IsSystem); 959 } 960 else 961 { 962 /* Can't blame a driver, assume system */ 963 IsSystem = TRUE; 964 } 965 966 /* FIXME: Check for session pool in addition to special pool */ 967 968 /* Special pool has its own bug check codes */ 969 if (MmIsSpecialPoolAddress((PVOID)BugCheckParameter1)) 970 { 971 if (MmIsSpecialPoolAddressFree((PVOID)BugCheckParameter1)) 972 { 973 KiBugCheckData[0] = IsSystem 974 ? PAGE_FAULT_IN_FREED_SPECIAL_POOL 975 : DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL; 976 } 977 else 978 { 979 KiBugCheckData[0] = IsSystem 980 ? PAGE_FAULT_BEYOND_END_OF_ALLOCATION 981 : DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION; 982 } 983 } 984 else if (!DriverBase) 985 { 986 /* Find the driver that unloaded at this address */ 987 KiBugCheckDriver = NULL; // FIXME: ROS can't locate 988 989 /* Check if the cause was an unloaded driver */ 990 if (KiBugCheckDriver) 991 { 992 KiBugCheckData[0] = 993 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS; 994 } 995 } 996 break; 997 } 998 999 /* Check if the driver forgot to unlock pages */ 1000 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS: 1001 1002 /* Program Counter is in parameter 1 */ 1003 Pc = (PVOID)BugCheckParameter1; 1004 break; 1005 1006 /* Check if the driver consumed too many PTEs */ 1007 case DRIVER_USED_EXCESSIVE_PTES: 1008 1009 /* Loader entry is in parameter 1 */ 1010 LdrEntry = (PVOID)BugCheckParameter1; 1011 KiBugCheckDriver = &LdrEntry->BaseDllName; 1012 break; 1013 1014 /* Check if the driver has a stuck thread */ 1015 case THREAD_STUCK_IN_DEVICE_DRIVER: 1016 1017 /* The name is in Parameter 3 */ 1018 KiBugCheckDriver = (PVOID)BugCheckParameter3; 1019 break; 1020 1021 /* Anything else */ 1022 default: 1023 break; 1024 } 1025 1026 /* Do we have a driver name? */ 1027 if (KiBugCheckDriver) 1028 { 1029 /* Convert it to ANSI */ 1030 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName)); 1031 } 1032 else 1033 { 1034 /* Do we have a Program Counter? */ 1035 if (Pc) 1036 { 1037 /* Dump image name */ 1038 KiDumpParameterImages(AnsiName, 1039 (PULONG_PTR)&Pc, 1040 1, 1041 KeBugCheckUnicodeToAnsi); 1042 } 1043 } 1044 1045 /* Check if we need to save the context for KD */ 1046 if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG_PTR)&Context; 1047 1048 /* Check if a debugger is connected */ 1049 if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled)) 1050 { 1051 /* Crash on the debugger console */ 1052 DbgPrint("\n*** Fatal System Error: 0x%08lx\n" 1053 " (0x%p,0x%p,0x%p,0x%p)\n\n", 1054 KiBugCheckData[0], 1055 KiBugCheckData[1], 1056 KiBugCheckData[2], 1057 KiBugCheckData[3], 1058 KiBugCheckData[4]); 1059 1060 /* Check if the debugger isn't currently connected */ 1061 if (!KdDebuggerNotPresent) 1062 { 1063 /* Check if we have a driver to blame */ 1064 if (KiBugCheckDriver) 1065 { 1066 /* Dump it */ 1067 DbgPrint("Driver at fault: %s.\n", AnsiName); 1068 } 1069 1070 /* Check if this was a hard error */ 1071 if (IsHardError) 1072 { 1073 /* Print caption and message */ 1074 if (HardErrCaption) DbgPrint(HardErrCaption); 1075 if (HardErrMessage) DbgPrint(HardErrMessage); 1076 } 1077 1078 /* Break in the debugger */ 1079 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST); 1080 } 1081 } 1082 1083 /* Raise IRQL to HIGH_LEVEL */ 1084 _disable(); 1085 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 1086 1087 /* Avoid recursion */ 1088 if (!InterlockedDecrement((PLONG)&KeBugCheckCount)) 1089 { 1090 #ifdef CONFIG_SMP 1091 /* Set CPU that is bug checking now */ 1092 KeBugCheckOwner = Prcb->Number; 1093 1094 /* Freeze the other CPUs */ 1095 KxFreezeExecution(); 1096 #endif 1097 1098 /* Display the BSOD */ 1099 KiDisplayBlueScreen(MessageId, 1100 IsHardError, 1101 HardErrCaption, 1102 HardErrMessage, 1103 AnsiName); 1104 1105 // TODO/FIXME: Run the registered reason-callbacks from 1106 // the KeBugcheckReasonCallbackListHead list with the 1107 // KbCallbackReserved1 reason. 1108 1109 /* Check if the debugger is disabled but we can enable it */ 1110 if (!(KdDebuggerEnabled) && !(KdPitchDebugger)) 1111 { 1112 /* Enable it */ 1113 KdEnableDebuggerWithLock(FALSE); 1114 } 1115 else 1116 { 1117 /* Otherwise, print the last line */ 1118 InbvDisplayString("\r\n"); 1119 } 1120 1121 /* Save the context */ 1122 Prcb->ProcessorState.ContextFrame = Context; 1123 1124 /* FIXME: Support Triage Dump */ 1125 1126 /* FIXME: Write the crash dump */ 1127 // TODO: The crash-dump helper must set the Reboot variable. 1128 Reboot = !!IopAutoReboot; 1129 } 1130 else 1131 { 1132 /* Increase recursion count */ 1133 KeBugCheckOwnerRecursionCount++; 1134 if (KeBugCheckOwnerRecursionCount == 2) 1135 { 1136 /* Break in the debugger */ 1137 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND); 1138 } 1139 else if (KeBugCheckOwnerRecursionCount > 2) 1140 { 1141 /* Halt execution */ 1142 while (TRUE); 1143 } 1144 } 1145 1146 /* Call the Callbacks */ 1147 KiDoBugCheckCallbacks(); 1148 1149 /* FIXME: Call Watchdog if enabled */ 1150 1151 /* Check if we have to reboot */ 1152 if (Reboot) 1153 { 1154 /* Unload symbols */ 1155 DbgUnLoadImageSymbols(NULL, (PVOID)MAXULONG_PTR, 0); 1156 HalReturnToFirmware(HalRebootRoutine); 1157 } 1158 1159 /* Attempt to break in the debugger (otherwise halt CPU) */ 1160 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND); 1161 1162 /* Shouldn't get here */ 1163 ASSERT(FALSE); 1164 while (TRUE); 1165 } 1166 1167 BOOLEAN 1168 NTAPI 1169 KiHandleNmi(VOID) 1170 { 1171 BOOLEAN Handled = FALSE; 1172 PKNMI_HANDLER_CALLBACK NmiData; 1173 1174 /* Parse the list of callbacks */ 1175 NmiData = KiNmiCallbackListHead; 1176 while (NmiData) 1177 { 1178 /* Save if this callback has handled it -- all it takes is one */ 1179 Handled |= NmiData->Callback(NmiData->Context, Handled); 1180 NmiData = NmiData->Next; 1181 } 1182 1183 /* Has anyone handled this? */ 1184 return Handled; 1185 } 1186 1187 /* PUBLIC FUNCTIONS **********************************************************/ 1188 1189 /* 1190 * @unimplemented 1191 */ 1192 NTSTATUS 1193 NTAPI 1194 KeInitializeCrashDumpHeader(IN ULONG Type, 1195 IN ULONG Flags, 1196 OUT PVOID Buffer, 1197 IN ULONG BufferSize, 1198 OUT ULONG BufferNeeded OPTIONAL) 1199 { 1200 UNIMPLEMENTED; 1201 return STATUS_UNSUCCESSFUL; 1202 } 1203 1204 /* 1205 * @implemented 1206 */ 1207 BOOLEAN 1208 NTAPI 1209 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord) 1210 { 1211 KIRQL OldIrql; 1212 BOOLEAN Status = FALSE; 1213 1214 /* Raise IRQL to High */ 1215 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 1216 1217 /* Check the Current State */ 1218 if (CallbackRecord->State == BufferInserted) 1219 { 1220 /* Reset state and remove from list */ 1221 CallbackRecord->State = BufferEmpty; 1222 RemoveEntryList(&CallbackRecord->Entry); 1223 Status = TRUE; 1224 } 1225 1226 /* Lower IRQL and return */ 1227 KeLowerIrql(OldIrql); 1228 return Status; 1229 } 1230 1231 /* 1232 * @implemented 1233 */ 1234 BOOLEAN 1235 NTAPI 1236 KeDeregisterBugCheckReasonCallback( 1237 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord) 1238 { 1239 KIRQL OldIrql; 1240 BOOLEAN Status = FALSE; 1241 1242 /* Raise IRQL to High */ 1243 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 1244 1245 /* Check the Current State */ 1246 if (CallbackRecord->State == BufferInserted) 1247 { 1248 /* Reset state and remove from list */ 1249 CallbackRecord->State = BufferEmpty; 1250 RemoveEntryList(&CallbackRecord->Entry); 1251 Status = TRUE; 1252 } 1253 1254 /* Lower IRQL and return */ 1255 KeLowerIrql(OldIrql); 1256 return Status; 1257 } 1258 1259 /* 1260 * @implemented 1261 */ 1262 BOOLEAN 1263 NTAPI 1264 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord, 1265 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine, 1266 IN PVOID Buffer, 1267 IN ULONG Length, 1268 IN PUCHAR Component) 1269 { 1270 KIRQL OldIrql; 1271 BOOLEAN Status = FALSE; 1272 1273 /* Raise IRQL to High */ 1274 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 1275 1276 /* Check the Current State first so we don't double-register */ 1277 if (CallbackRecord->State == BufferEmpty) 1278 { 1279 /* Set the Callback Settings and insert into the list */ 1280 CallbackRecord->Length = Length; 1281 CallbackRecord->Buffer = Buffer; 1282 CallbackRecord->Component = Component; 1283 CallbackRecord->CallbackRoutine = CallbackRoutine; 1284 CallbackRecord->State = BufferInserted; 1285 InsertTailList(&KeBugcheckCallbackListHead, &CallbackRecord->Entry); 1286 Status = TRUE; 1287 } 1288 1289 /* Lower IRQL and return */ 1290 KeLowerIrql(OldIrql); 1291 return Status; 1292 } 1293 1294 /* 1295 * @implemented 1296 */ 1297 BOOLEAN 1298 NTAPI 1299 KeRegisterBugCheckReasonCallback( 1300 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord, 1301 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine, 1302 IN KBUGCHECK_CALLBACK_REASON Reason, 1303 IN PUCHAR Component) 1304 { 1305 KIRQL OldIrql; 1306 BOOLEAN Status = FALSE; 1307 1308 /* Raise IRQL to High */ 1309 KeRaiseIrql(HIGH_LEVEL, &OldIrql); 1310 1311 /* Check the Current State first so we don't double-register */ 1312 if (CallbackRecord->State == BufferEmpty) 1313 { 1314 /* Set the Callback Settings and insert into the list */ 1315 CallbackRecord->Component = Component; 1316 CallbackRecord->CallbackRoutine = CallbackRoutine; 1317 CallbackRecord->State = BufferInserted; 1318 CallbackRecord->Reason = Reason; 1319 InsertTailList(&KeBugcheckReasonCallbackListHead, 1320 &CallbackRecord->Entry); 1321 Status = TRUE; 1322 } 1323 1324 /* Lower IRQL and return */ 1325 KeLowerIrql(OldIrql); 1326 return Status; 1327 } 1328 1329 /* 1330 * @implemented 1331 */ 1332 PVOID 1333 NTAPI 1334 KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine, 1335 IN PVOID Context) 1336 { 1337 KIRQL OldIrql; 1338 PKNMI_HANDLER_CALLBACK NmiData, Next; 1339 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 1340 1341 /* Allocate NMI callback data */ 1342 NmiData = ExAllocatePoolWithTag(NonPagedPool, sizeof(*NmiData), TAG_KNMI); 1343 if (!NmiData) return NULL; 1344 1345 /* Fill in the information */ 1346 NmiData->Callback = CallbackRoutine; 1347 NmiData->Context = Context; 1348 NmiData->Handle = NmiData; 1349 1350 /* Insert it into NMI callback list */ 1351 KiAcquireNmiListLock(&OldIrql); 1352 NmiData->Next = KiNmiCallbackListHead; 1353 Next = InterlockedCompareExchangePointer((PVOID*)&KiNmiCallbackListHead, 1354 NmiData, 1355 NmiData->Next); 1356 ASSERT(Next == NmiData->Next); 1357 KiReleaseNmiListLock(OldIrql); 1358 1359 /* Return the opaque "handle" */ 1360 return NmiData->Handle; 1361 } 1362 1363 /* 1364 * @implemented 1365 */ 1366 NTSTATUS 1367 NTAPI 1368 KeDeregisterNmiCallback(IN PVOID Handle) 1369 { 1370 KIRQL OldIrql; 1371 PKNMI_HANDLER_CALLBACK NmiData; 1372 PKNMI_HANDLER_CALLBACK* Previous; 1373 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 1374 1375 /* Find in the list the NMI callback corresponding to the handle */ 1376 KiAcquireNmiListLock(&OldIrql); 1377 Previous = &KiNmiCallbackListHead; 1378 NmiData = *Previous; 1379 while (NmiData) 1380 { 1381 if (NmiData->Handle == Handle) 1382 { 1383 /* The handle is the pointer to the callback itself */ 1384 ASSERT(Handle == NmiData); 1385 1386 /* Found it, remove from the list */ 1387 *Previous = NmiData->Next; 1388 break; 1389 } 1390 1391 /* Not found; try again */ 1392 Previous = &NmiData->Next; 1393 NmiData = *Previous; 1394 } 1395 KiReleaseNmiListLock(OldIrql); 1396 1397 /* If we have found the entry, free it */ 1398 if (NmiData) 1399 { 1400 ExFreePoolWithTag(NmiData, TAG_KNMI); 1401 return STATUS_SUCCESS; 1402 } 1403 1404 return STATUS_INVALID_HANDLE; 1405 } 1406 1407 /* 1408 * @implemented 1409 */ 1410 DECLSPEC_NORETURN 1411 VOID 1412 NTAPI 1413 KeBugCheckEx(IN ULONG BugCheckCode, 1414 IN ULONG_PTR BugCheckParameter1, 1415 IN ULONG_PTR BugCheckParameter2, 1416 IN ULONG_PTR BugCheckParameter3, 1417 IN ULONG_PTR BugCheckParameter4) 1418 { 1419 /* Call the internal API */ 1420 KeBugCheckWithTf(BugCheckCode, 1421 BugCheckParameter1, 1422 BugCheckParameter2, 1423 BugCheckParameter3, 1424 BugCheckParameter4, 1425 NULL); 1426 } 1427 1428 /* 1429 * @implemented 1430 */ 1431 DECLSPEC_NORETURN 1432 VOID 1433 NTAPI 1434 KeBugCheck(ULONG BugCheckCode) 1435 { 1436 /* Call the internal API */ 1437 KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL); 1438 } 1439 1440 /* 1441 * @implemented 1442 */ 1443 VOID 1444 NTAPI 1445 KeEnterKernelDebugger(VOID) 1446 { 1447 /* Disable interrupts */ 1448 KiHardwareTrigger = 1; 1449 _disable(); 1450 1451 /* Check the bugcheck count */ 1452 if (!InterlockedDecrement((PLONG)&KeBugCheckCount)) 1453 { 1454 /* There was only one, is the debugger disabled? */ 1455 if (!(KdDebuggerEnabled) && !(KdPitchDebugger)) 1456 { 1457 /* Enable the debugger */ 1458 KdInitSystem(0, NULL); 1459 } 1460 } 1461 1462 /* Break in the debugger */ 1463 KiBugCheckDebugBreak(DBG_STATUS_FATAL); 1464 } 1465 1466 /* EOF */ 1467