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