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