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