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)
9 /* INCLUDES ******************************************************************/
15 #if defined (ALLOC_PRAGMA)
16 #pragma alloc_text(INIT, KiInitializeBugCheck)
19 /* GLOBALS *******************************************************************/
21 LIST_ENTRY KeBugcheckCallbackListHead
;
22 LIST_ENTRY KeBugcheckReasonCallbackListHead
;
23 KSPIN_LOCK BugCheckCallbackLock
;
24 ULONG KeBugCheckActive
, KeBugCheckOwner
;
25 LONG KeBugCheckOwnerRecursionCount
;
26 PMESSAGE_RESOURCE_DATA KiBugCodeMessages
;
27 ULONG KeBugCheckCount
= 1;
28 ULONG KiHardwareTrigger
;
29 PUNICODE_STRING KiBugCheckDriver
;
30 ULONG_PTR KiBugCheckData
[5];
31 PKNMI_HANDLER_CALLBACK KiNmiCallbackListHead
;
32 KSPIN_LOCK KiNmiCallbackListLock
;
34 /* Bugzilla Reporting */
35 UNICODE_STRING KeRosProcessorName
, KeRosBiosDate
, KeRosBiosVersion
;
36 UNICODE_STRING KeRosVideoBiosDate
, KeRosVideoBiosVersion
;
38 /* PRIVATE FUNCTIONS *********************************************************/
42 KiPcToFileHeader(IN PVOID Pc
,
43 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
,
44 IN BOOLEAN DriversOnly
,
45 OUT PBOOLEAN InKernel
)
48 PVOID ImageBase
, PcBase
= NULL
;
49 PLDR_DATA_TABLE_ENTRY Entry
;
50 PLIST_ENTRY ListHead
, NextEntry
;
52 /* Check which list we should use */
53 ListHead
= (KeLoaderBlock
) ? &KeLoaderBlock
->LoadOrderListHead
:
59 /* Set list pointers and make sure it's valid */
60 NextEntry
= ListHead
->Flink
;
64 while (NextEntry
!= ListHead
)
69 /* Check if this is a kernel entry and we only want drivers */
70 if ((i
<= 2) && (DriversOnly
== TRUE
))
73 NextEntry
= NextEntry
->Flink
;
77 /* Get the loader entry */
78 Entry
= CONTAINING_RECORD(NextEntry
,
82 /* Move to the next entry */
83 NextEntry
= NextEntry
->Flink
;
84 ImageBase
= Entry
->DllBase
;
86 /* Check if this is the right one */
87 if (((ULONG_PTR
)Pc
>= (ULONG_PTR
)Entry
->DllBase
) &&
88 ((ULONG_PTR
)Pc
< ((ULONG_PTR
)Entry
->DllBase
+ Entry
->SizeOfImage
)))
90 /* Return this entry */
94 /* Check if this was a kernel or HAL entry */
95 if (i
<= 2) *InKernel
= TRUE
;
101 /* Return the base address */
107 KiRosPrintAddress(PVOID address
)
109 PLIST_ENTRY current_entry
;
110 PLDR_DATA_TABLE_ENTRY current
;
111 extern LIST_ENTRY PsLoadedModuleList
;
112 ULONG_PTR RelativeAddress
;
117 current_entry
= PsLoadedModuleList
.Flink
;
119 while (current_entry
!= &PsLoadedModuleList
)
121 current
= CONTAINING_RECORD(current_entry
,
122 LDR_DATA_TABLE_ENTRY
,
125 if (address
>= (PVOID
)current
->DllBase
&&
126 address
< (PVOID
)((ULONG_PTR
)current
->DllBase
+
127 current
->SizeOfImage
))
129 RelativeAddress
= (ULONG_PTR
)address
-
130 (ULONG_PTR
)current
->DllBase
;
131 DbgPrint("<%wZ: %x>", ¤t
->FullDllName
, RelativeAddress
);
134 current_entry
= current_entry
->Flink
;
143 KiRosPcToUserFileHeader(IN PVOID Pc
,
144 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
146 PVOID ImageBase
, PcBase
= NULL
;
147 PLDR_DATA_TABLE_ENTRY Entry
;
148 PLIST_ENTRY ListHead
, NextEntry
;
151 * We know this is valid because we should only be called after a
152 * succesfull address from RtlWalkFrameChain for UserMode, which
153 * validates everything for us.
155 ListHead
= &KeGetCurrentThread()->
156 Teb
->ProcessEnvironmentBlock
->Ldr
->InLoadOrderModuleList
;
158 /* Set list pointers and make sure it's valid */
159 NextEntry
= ListHead
->Flink
;
163 while (NextEntry
!= ListHead
)
165 /* Get the loader entry */
166 Entry
= CONTAINING_RECORD(NextEntry
,
167 LDR_DATA_TABLE_ENTRY
,
170 /* Move to the next entry */
171 NextEntry
= NextEntry
->Flink
;
172 ImageBase
= Entry
->DllBase
;
174 /* Check if this is the right one */
175 if (((ULONG_PTR
)Pc
>= (ULONG_PTR
)Entry
->DllBase
) &&
176 ((ULONG_PTR
)Pc
< ((ULONG_PTR
)Entry
->DllBase
+ Entry
->SizeOfImage
)))
178 /* Return this entry */
186 /* Return the base address */
192 KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip
,
193 IN ULONG FramesToCapture
,
194 OUT PVOID
*BackTrace
,
195 OUT PULONG BackTraceHash OPTIONAL
)
197 PVOID Frames
[2 * 64];
201 /* Skip a frame for the caller */
204 /* Don't go past the limit */
205 if ((FramesToCapture
+ FramesToSkip
) >= 128) return 0;
207 /* Do the back trace */
208 FrameCount
= RtlWalkFrameChain(Frames
, FramesToCapture
+ FramesToSkip
, 1);
210 /* Make sure we're not skipping all of them */
211 if (FrameCount
<= FramesToSkip
) return 0;
213 /* Loop all the frames */
214 for (i
= 0; i
< FramesToCapture
; i
++)
216 /* Don't go past the limit */
217 if ((FramesToSkip
+ i
) >= FrameCount
) break;
219 /* Save this entry and hash it */
220 BackTrace
[i
] = Frames
[FramesToSkip
+ i
];
221 Hash
+= PtrToUlong(BackTrace
[i
]);
225 if (BackTraceHash
) *BackTraceHash
= Hash
;
227 /* Clear the other entries and return count */
228 RtlFillMemoryUlong(Frames
, 128, 0);
235 KeRosDumpStackFrameArray(IN PULONG_PTR Frames
,
243 /* GCC complaints that it may be used uninitialized */
244 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
247 for (i
= 0; i
< FrameCount
; i
++)
256 /* Get the base for this file */
257 if (Addr
> (ULONG_PTR
)MmHighestUserAddress
)
259 /* We are in kernel */
260 p
= KiPcToFileHeader((PVOID
)Addr
, &LdrEntry
, FALSE
, &InSystem
);
264 /* We are in user land */
265 p
= KiRosPcToUserFileHeader((PVOID
)Addr
, &LdrEntry
);
270 if (!KdbSymPrintAddress((PVOID
)Addr
, NULL
))
273 /* Print out the module name */
274 Addr
-= (ULONG_PTR
)LdrEntry
->DllBase
;
275 DbgPrint("<%wZ: %p>", &LdrEntry
->FullDllName
, (PVOID
)Addr
);
280 /* Print only the address */
281 DbgPrint("<%p>", (PVOID
)Addr
);
284 /* Go to the next frame */
291 KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL
,
292 IN ULONG FrameCount OPTIONAL
)
294 ULONG_PTR Frames
[32];
295 ULONG RealFrameCount
;
297 /* If the caller didn't ask, assume 32 frames */
298 if (!FrameCount
|| FrameCount
> 32) FrameCount
= 32;
303 KeRosDumpStackFrameArray(Frame
, FrameCount
);
307 /* Get the current frames (skip the two. One for the dumper, one for the caller) */
308 RealFrameCount
= RtlCaptureStackBackTrace(2, FrameCount
, (PVOID
*)Frames
, NULL
);
311 KeRosDumpStackFrameArray(Frames
, RealFrameCount
);
313 /* Count left for user mode? */
314 if (FrameCount
- RealFrameCount
> 0)
316 /* Get the current frames */
317 RealFrameCount
= KeRosCaptureUserStackBackTrace(-1, FrameCount
- RealFrameCount
, (PVOID
*)Frames
, NULL
);
320 KeRosDumpStackFrameArray(Frames
, RealFrameCount
);
327 KeRosDumpTriageForBugZillaReport(VOID
)
330 extern BOOLEAN KiFastSystemCallDisable
, KiSMTProcessorsPresent
;
331 extern ULONG KeI386MachineType
, MxcsrFeatureMask
;
332 extern BOOLEAN Ke386Pae
, Ke386NoExecute
;
334 DbgPrint("ReactOS has crashed! Please go to http://www.reactos.org/bugzilla/enter_bug.cgi to file a bug!\n");
335 DbgPrint("\nHardware Information\n");
336 DbgPrint("Processor Architecture: %d\n"
338 "System Call Disabled: %d\n"
341 "MXCsr Feature Mask: %d\n"
348 "Active Processors: %d\n"
349 "Pentium LOCK Bug: %d\n"
350 "Hyperthreading: %d\n"
351 "CPU Manufacturer: %s\n"
359 "BIOS Version: %wZ\n"
360 "Video BIOS Date: %wZ\n"
361 "Video BIOS Version: %wZ\n"
363 KeProcessorArchitecture
,
365 KiFastSystemCallDisable
,
376 KiI386PentiumLockErrataPresent
,
377 KiSMTProcessorsPresent
,
378 KeGetCurrentPrcb()->VendorString
,
380 KeGetCurrentPrcb()->CpuID
,
381 KeGetCurrentPrcb()->CpuType
,
382 KeGetCurrentPrcb()->CpuStep
,
383 KeGetCurrentPrcb()->MHz
,
384 ((PKIPCR
)KeGetPcr())->SecondLevelCacheSize
,
388 &KeRosVideoBiosVersion
,
389 MmNumberOfPhysicalPages
* PAGE_SIZE
);
396 KiInitializeBugCheck(VOID
)
398 PMESSAGE_RESOURCE_DATA BugCheckData
;
399 LDR_RESOURCE_INFO ResourceInfo
;
400 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
402 PLDR_DATA_TABLE_ENTRY LdrEntry
;
404 /* Get the kernel entry */
405 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
,
406 LDR_DATA_TABLE_ENTRY
,
409 /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
410 ResourceInfo
.Type
= 11;
411 ResourceInfo
.Name
= 1;
412 ResourceInfo
.Language
= 9;
415 Status
= LdrFindResource_U(LdrEntry
->DllBase
,
420 /* Make sure it worked */
421 if (NT_SUCCESS(Status
))
423 /* Now actually get a pointer to it */
424 Status
= LdrAccessResource(LdrEntry
->DllBase
,
426 (PVOID
*)&BugCheckData
,
428 if (NT_SUCCESS(Status
)) KiBugCodeMessages
= BugCheckData
;
434 KeGetBugMessageText(IN ULONG BugCheckCode
,
435 OUT PANSI_STRING OutputString OPTIONAL
)
439 ULONG_PTR MessageEntry
;
441 BOOLEAN Result
= FALSE
;
444 /* Make sure we're not bugchecking too early */
445 if (!KiBugCodeMessages
) return Result
;
447 /* Find the message. This code is based on RtlFindMesssage */
448 for (i
= 0; i
< KiBugCodeMessages
->NumberOfBlocks
; i
++)
450 /* Check if the ID Matches */
451 if ((BugCheckCode
>= KiBugCodeMessages
->Blocks
[i
].LowId
) &&
452 (BugCheckCode
<= KiBugCodeMessages
->Blocks
[i
].HighId
))
454 /* Get Offset to Entry */
455 MessageEntry
= KiBugCodeMessages
->Blocks
[i
].OffsetToEntries
+
456 (ULONG_PTR
)KiBugCodeMessages
;
457 IdOffset
= BugCheckCode
- KiBugCodeMessages
->Blocks
[i
].LowId
;
459 /* Get offset to ID */
460 for (j
= 0; j
< IdOffset
; j
++)
462 /* Advance in the Entries */
463 MessageEntry
+= ((PMESSAGE_RESOURCE_ENTRY
)MessageEntry
)->
467 /* Get the final Code */
468 BugCode
= (PCHAR
)((PMESSAGE_RESOURCE_ENTRY
)MessageEntry
)->Text
;
469 Length
= (USHORT
)strlen(BugCode
);
471 /* Handle trailing newlines */
472 while ((Length
> 0) && ((BugCode
[Length
] == '\n') ||
473 (BugCode
[Length
] == '\r') ||
474 (BugCode
[Length
] == ANSI_NULL
)))
476 /* Check if we have a string to return */
477 if (!OutputString
) BugCode
[Length
] = ANSI_NULL
;
481 /* Check if caller wants an output string */
484 /* Return it in the OutputString */
485 OutputString
->Buffer
= BugCode
;
486 OutputString
->Length
= Length
+ 1;
487 OutputString
->MaximumLength
= Length
+ 1;
491 /* Direct Output to Screen */
492 InbvDisplayString(BugCode
);
493 InbvDisplayString("\r");
502 /* Return the result */
508 KiDoBugCheckCallbacks(VOID
)
510 PKBUGCHECK_CALLBACK_RECORD CurrentRecord
;
511 PLIST_ENTRY ListHead
, NextEntry
, LastEntry
;
514 /* First make sure that the list is Initialized... it might not be */
515 ListHead
= &KeBugcheckCallbackListHead
;
516 if ((ListHead
->Flink
) && (ListHead
->Blink
))
519 LastEntry
= ListHead
;
520 NextEntry
= ListHead
->Flink
;
521 while (NextEntry
!= ListHead
)
524 CurrentRecord
= CONTAINING_RECORD(NextEntry
,
525 KBUGCHECK_CALLBACK_RECORD
,
529 if (CurrentRecord
->Entry
.Blink
!= LastEntry
) return;
530 Checksum
= (ULONG_PTR
)CurrentRecord
->CallbackRoutine
;
531 Checksum
+= (ULONG_PTR
)CurrentRecord
->Buffer
;
532 Checksum
+= (ULONG_PTR
)CurrentRecord
->Length
;
533 Checksum
+= (ULONG_PTR
)CurrentRecord
->Component
;
535 /* Make sure it's inserted and valitdated */
536 if ((CurrentRecord
->State
== BufferInserted
) &&
537 (CurrentRecord
->Checksum
== Checksum
))
539 /* Call the routine */
540 CurrentRecord
->State
= BufferStarted
;
541 (CurrentRecord
->CallbackRoutine
)(CurrentRecord
->Buffer
,
542 CurrentRecord
->Length
);
543 CurrentRecord
->State
= BufferFinished
;
546 /* Go to the next entry */
547 LastEntry
= NextEntry
;
548 NextEntry
= NextEntry
->Flink
;
555 KiBugCheckDebugBreak(IN ULONG StatusCode
)
558 * Wrap this in SEH so we don't crash if
559 * there is no debugger or if it disconnected
565 DbgBreakPointWithStatus(StatusCode
);
567 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
569 /* No debugger, halt the CPU */
574 /* Break again if this wasn't first try */
575 if (StatusCode
!= DBG_STATUS_BUGCHECK_FIRST
) goto DoBreak
;
580 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode
,
588 /* Set length and normalize it */
589 i
= Unicode
->Length
/ sizeof(WCHAR
);
590 i
= min(i
, Length
- 1);
592 /* Set source and destination, and copy */
593 pw
= Unicode
->Buffer
;
595 while (i
--) *p
++ = (CHAR
)*pw
++;
597 /* Null terminate and return */
604 KiDumpParameterImages(IN PCHAR Message
,
605 IN PULONG_PTR Parameters
,
606 IN ULONG ParameterCount
,
607 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine
)
611 PLDR_DATA_TABLE_ENTRY LdrEntry
;
613 PUNICODE_STRING DriverName
;
615 PIMAGE_NT_HEADERS NtHeader
;
617 BOOLEAN FirstRun
= TRUE
;
619 /* Loop parameters */
620 for (i
= 0; i
< ParameterCount
; i
++)
622 /* Get the base for this parameter */
623 ImageBase
= KiPcToFileHeader((PVOID
)Parameters
[i
],
629 /* FIXME: Add code to check for unloaded drivers */
630 DPRINT1("Potentially unloaded driver!\n");
635 /* Get the NT Headers and Timestamp */
636 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
637 TimeStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
639 /* Convert the driver name */
640 DriverName
= &LdrEntry
->BaseDllName
;
641 ConversionRoutine(&LdrEntry
->BaseDllName
,
646 /* Format driver name */
648 "%s** %12s - Address %p base at %p, DateStamp %08lx\n",
649 FirstRun
? "\r\n*":"*",
651 (PVOID
)Parameters
[i
],
655 /* Check if we only had one parameter */
656 if (ParameterCount
<= 1)
658 /* Then just save the name */
659 KiBugCheckDriver
= DriverName
;
663 /* Otherwise, display the message */
664 InbvDisplayString(Message
);
674 KiDisplayBlueScreen(IN ULONG MessageId
,
675 IN BOOLEAN IsHardError
,
676 IN PCHAR HardErrCaption OPTIONAL
,
677 IN PCHAR HardErrMessage OPTIONAL
,
682 /* Check if bootvid is installed */
683 if (InbvIsBootDriverInstalled())
685 /* Acquire ownership and reset the display */
686 InbvAcquireDisplayOwnership();
689 /* Display blue screen */
690 InbvSolidColorFill(0, 0, 639, 479, 4);
691 InbvSetTextColor(15);
692 InbvInstallDisplayStringFilter(NULL
);
693 InbvEnableDisplayString(TRUE
);
694 InbvSetScrollRegion(0, 0, 639, 479);
697 /* Check if this is a hard error */
700 /* Display caption and message */
701 if (HardErrCaption
) InbvDisplayString(HardErrCaption
);
702 if (HardErrMessage
) InbvDisplayString(HardErrMessage
);
705 /* Begin the display */
706 InbvDisplayString("\r\n");
708 /* Print out initial message */
709 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO
, NULL
);
710 InbvDisplayString("\r\n\r\n");
712 /* Check if we have a driver */
713 if (KiBugCheckDriver
)
715 /* Print out into to driver name */
716 KeGetBugMessageText(BUGCODE_ID_DRIVER
, NULL
);
718 /* Convert and print out driver name */
719 KeBugCheckUnicodeToAnsi(KiBugCheckDriver
, AnsiName
, sizeof(AnsiName
));
720 InbvDisplayString(" ");
721 InbvDisplayString(AnsiName
);
722 InbvDisplayString("\r\n\r\n");
725 /* Check if this is the generic message */
726 if (MessageId
== BUGCODE_PSS_MESSAGE
)
728 /* It is, so get the bug code string as well */
729 KeGetBugMessageText((ULONG
)KiBugCheckData
[0], NULL
);
730 InbvDisplayString("\r\n\r\n");
733 /* Print second introduction message */
734 KeGetBugMessageText(PSS_MESSAGE_INTRO
, NULL
);
735 InbvDisplayString("\r\n\r\n");
737 /* Get the bug code string */
738 KeGetBugMessageText(MessageId
, NULL
);
739 InbvDisplayString("\r\n\r\n");
741 /* Print message for technical information */
742 KeGetBugMessageText(BUGCHECK_TECH_INFO
, NULL
);
744 /* Show the technical Data */
746 "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
748 (PVOID
)KiBugCheckData
[1],
749 (PVOID
)KiBugCheckData
[2],
750 (PVOID
)KiBugCheckData
[3],
751 (PVOID
)KiBugCheckData
[4]);
752 InbvDisplayString(AnsiName
);
754 /* Check if we have a driver*/
755 if (KiBugCheckDriver
)
757 /* Display technical driver data */
758 InbvDisplayString(Message
);
762 /* Dump parameter information */
763 KiDumpParameterImages(Message
,
764 (PVOID
)&KiBugCheckData
[1],
766 KeBugCheckUnicodeToAnsi
);
772 KeBugCheckWithTf(IN ULONG BugCheckCode
,
773 IN ULONG_PTR BugCheckParameter1
,
774 IN ULONG_PTR BugCheckParameter2
,
775 IN ULONG_PTR BugCheckParameter3
,
776 IN ULONG_PTR BugCheckParameter4
,
777 IN PKTRAP_FRAME TrapFrame
)
779 PKPRCB Prcb
= KeGetCurrentPrcb();
783 BOOLEAN IsSystem
, IsHardError
= FALSE
, Reboot
= FALSE
;
784 PCHAR HardErrCaption
= NULL
, HardErrMessage
= NULL
;
785 PVOID Pc
= NULL
, Memory
;
787 PLDR_DATA_TABLE_ENTRY LdrEntry
;
788 PULONG_PTR HardErrorParameters
;
794 /* Set active bugcheck */
795 KeBugCheckActive
= TRUE
;
796 KiBugCheckDriver
= NULL
;
798 /* Check if this is power failure simulation */
799 if (BugCheckCode
== POWER_FAILURE_SIMULATE
)
801 /* Call the Callbacks and reboot */
802 KiDoBugCheckCallbacks();
803 HalReturnToFirmware(HalRebootRoutine
);
806 /* Save the IRQL and set hardware trigger */
807 Prcb
->DebuggerSavedIRQL
= KeGetCurrentIrql();
808 InterlockedIncrement((PLONG
)&KiHardwareTrigger
);
810 /* Capture the CPU Context */
811 RtlCaptureContext(&Prcb
->ProcessorState
.ContextFrame
);
812 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
813 Context
= Prcb
->ProcessorState
.ContextFrame
;
815 /* FIXME: Call the Watchdog if it's registered */
817 /* Check which bugcode this is */
818 switch (BugCheckCode
)
820 /* These bug checks already have detailed messages, keep them */
821 case UNEXPECTED_KERNEL_MODE_TRAP
:
822 case DRIVER_CORRUPTED_EXPOOL
:
823 case ACPI_BIOS_ERROR
:
824 case ACPI_BIOS_FATAL_ERROR
:
825 case THREAD_STUCK_IN_DEVICE_DRIVER
:
827 case FAT_FILE_SYSTEM
:
828 case NO_MORE_SYSTEM_PTES
:
829 case INACCESSIBLE_BOOT_DEVICE
:
831 /* Keep the same code */
832 MessageId
= BugCheckCode
;
835 /* Check if this is a kernel-mode exception */
836 case KERNEL_MODE_EXCEPTION_NOT_HANDLED
:
837 case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED
:
838 case KMODE_EXCEPTION_NOT_HANDLED
:
840 /* Use the generic text message */
841 MessageId
= KMODE_EXCEPTION_NOT_HANDLED
;
844 /* File-system errors */
845 case NTFS_FILE_SYSTEM
:
847 /* Use the generic message for FAT */
848 MessageId
= FAT_FILE_SYSTEM
;
851 /* Check if this is a coruption of the Mm's Pool */
852 case DRIVER_CORRUPTED_MMPOOL
:
854 /* Use generic corruption message */
855 MessageId
= DRIVER_CORRUPTED_EXPOOL
;
858 /* Check if this is a signature check failure */
859 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
:
861 /* Use the generic corruption message */
862 MessageId
= BUGCODE_PSS_MESSAGE_SIGNATURE
;
865 /* All other codes */
868 /* Use the default bugcheck message */
869 MessageId
= BUGCODE_PSS_MESSAGE
;
873 /* Save bugcheck data */
874 KiBugCheckData
[0] = BugCheckCode
;
875 KiBugCheckData
[1] = BugCheckParameter1
;
876 KiBugCheckData
[2] = BugCheckParameter2
;
877 KiBugCheckData
[3] = BugCheckParameter3
;
878 KiBugCheckData
[4] = BugCheckParameter4
;
880 /* Now check what bugcheck this is */
881 switch (BugCheckCode
)
883 /* Invalid access to R/O memory or Unhandled KM Exception */
884 case KERNEL_MODE_EXCEPTION_NOT_HANDLED
:
885 case ATTEMPTED_WRITE_TO_READONLY_MEMORY
:
886 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY
:
888 /* Check if we have a trap frame */
891 /* Use parameter 3 as a trap frame, if it exists */
892 if (BugCheckParameter3
) TrapFrame
= (PVOID
)BugCheckParameter3
;
895 /* Check if we got one now and if we need to get the Program Counter */
897 (BugCheckCode
!= KERNEL_MODE_EXCEPTION_NOT_HANDLED
))
899 /* Get the Program Counter */
900 Pc
= (PVOID
)KeGetTrapFramePc(TrapFrame
);
905 case IRQL_NOT_LESS_OR_EQUAL
:
908 * The NT kernel has 3 special sections:
909 * MISYSPTE, POOLMI and POOLCODE. The bug check code can
910 * determine in which of these sections this bugcode happened
911 * and provide a more detailed analysis. For now, we don't.
914 /* Program Counter is in parameter 4 */
915 Pc
= (PVOID
)BugCheckParameter4
;
917 /* Get the driver base */
918 DriverBase
= KiPcToFileHeader(Pc
,
925 * The error happened inside the kernel or HAL.
926 * Get the memory address that was being referenced.
928 Memory
= (PVOID
)BugCheckParameter1
;
930 /* Find to which driver it belongs */
931 DriverBase
= KiPcToFileHeader(Memory
,
937 /* Get the driver name and update the bug code */
938 KiBugCheckDriver
= &LdrEntry
->BaseDllName
;
939 KiBugCheckData
[0] = DRIVER_PORTION_MUST_BE_NONPAGED
;
943 /* Find the driver that unloaded at this address */
944 KiBugCheckDriver
= NULL
; // FIXME: ROS can't locate
946 /* Check if the cause was an unloaded driver */
947 if (KiBugCheckDriver
)
949 /* Update bug check code */
951 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD
;
957 /* Update the bug check code */
958 KiBugCheckData
[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL
;
961 /* Clear Pc so we don't look it up later */
966 case FATAL_UNHANDLED_HARD_ERROR
:
968 /* Copy bug check data from hard error */
969 HardErrorParameters
= (PULONG_PTR
)BugCheckParameter2
;
970 KiBugCheckData
[0] = BugCheckParameter1
;
971 KiBugCheckData
[1] = HardErrorParameters
[0];
972 KiBugCheckData
[2] = HardErrorParameters
[1];
973 KiBugCheckData
[3] = HardErrorParameters
[2];
974 KiBugCheckData
[4] = HardErrorParameters
[3];
976 /* Remember that this is hard error and set the caption/message */
978 HardErrCaption
= (PCHAR
)BugCheckParameter3
;
979 HardErrMessage
= (PCHAR
)BugCheckParameter4
;
983 case PAGE_FAULT_IN_NONPAGED_AREA
:
985 /* Assume no driver */
988 /* Check if we have a trap frame */
991 /* We don't, use parameter 3 if possible */
992 if (BugCheckParameter3
) TrapFrame
= (PVOID
)BugCheckParameter3
;
995 /* Check if we have a frame now */
998 /* Get the Program Counter */
999 Pc
= (PVOID
)KeGetTrapFramePc(TrapFrame
);
1000 KiBugCheckData
[3] = (ULONG_PTR
)Pc
;
1002 /* Find out if was in the kernel or drivers */
1003 DriverBase
= KiPcToFileHeader(Pc
,
1010 * Now we should check if this happened in:
1011 * 1) Special Pool 2) Free Special Pool 3) Session Pool
1012 * and update the bugcheck code appropriately.
1015 /* Check if we didn't have a driver base */
1018 /* Find the driver that unloaded at this address */
1019 KiBugCheckDriver
= NULL
; // FIXME: ROS can't locate
1021 /* Check if the cause was an unloaded driver */
1022 if (KiBugCheckDriver
)
1025 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS
;
1030 /* Check if the driver forgot to unlock pages */
1031 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS
:
1033 /* Program Counter is in parameter 1 */
1034 Pc
= (PVOID
)BugCheckParameter1
;
1037 /* Check if the driver consumed too many PTEs */
1038 case DRIVER_USED_EXCESSIVE_PTES
:
1040 /* Loader entry is in parameter 1 */
1041 LdrEntry
= (PVOID
)BugCheckParameter1
;
1042 KiBugCheckDriver
= &LdrEntry
->BaseDllName
;
1045 /* Check if the driver has a stuck thread */
1046 case THREAD_STUCK_IN_DEVICE_DRIVER
:
1048 /* The name is in Parameter 3 */
1049 KiBugCheckDriver
= (PVOID
)BugCheckParameter3
;
1057 /* Do we have a driver name? */
1058 if (KiBugCheckDriver
)
1060 /* Convert it to ANSI */
1061 KeBugCheckUnicodeToAnsi(KiBugCheckDriver
, AnsiName
, sizeof(AnsiName
));
1065 /* Do we have a Program Counter? */
1068 /* Dump image name */
1069 KiDumpParameterImages(AnsiName
,
1072 KeBugCheckUnicodeToAnsi
);
1076 /* Check if we need to save the context for KD */
1078 if (!KdPitchDebugger
) KdDebuggerDataBlock
.SavedContext
= (ULONG_PTR
)&Context
;
1081 /* Check if a debugger is connected */
1082 if ((BugCheckCode
!= MANUALLY_INITIATED_CRASH
) && (KdDebuggerEnabled
))
1084 /* Crash on the debugger console */
1085 DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
1086 " (0x%p,0x%p,0x%p,0x%p)\n\n",
1093 /* Check if the debugger isn't currently connected */
1094 if (!KdDebuggerNotPresent
)
1096 /* Check if we have a driver to blame */
1097 if (KiBugCheckDriver
)
1100 DbgPrint("Driver at fault: %s.\n", AnsiName
);
1103 /* Check if this was a hard error */
1106 /* Print caption and message */
1107 if (HardErrCaption
) DbgPrint(HardErrCaption
);
1108 if (HardErrMessage
) DbgPrint(HardErrMessage
);
1111 /* Break in the debugger */
1112 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST
);
1118 * Ok, so debugging is enabled, but KDBG isn't there.
1119 * We'll manually dump the stack for the user.
1121 KeRosDumpStackFrames(NULL
, 0);
1123 /* ROS HACK 2: Generate something useful for Bugzilla */
1124 KeRosDumpTriageForBugZillaReport();
1128 /* Raise IRQL to HIGH_LEVEL */
1130 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1132 /* Avoid recursion */
1133 if (!InterlockedDecrement((PLONG
)&KeBugCheckCount
))
1136 /* Set CPU that is bug checking now */
1137 KeBugCheckOwner
= Prcb
->Number
;
1139 /* Freeze the other CPUs */
1140 for (i
= 0; i
< KeNumberProcessors
; i
++)
1142 if (i
!= (LONG
)KeGetCurrentProcessorNumber())
1144 /* Send the IPI and give them one second to catch up */
1145 KiIpiSend(1 << i
, IPI_FREEZE
);
1146 KeStallExecutionProcessor(1000000);
1151 /* Display the BSOD */
1152 KiDisplayBlueScreen(MessageId
,
1158 /* Check if the debugger is disabled but we can enable it */
1159 if (!(KdDebuggerEnabled
) && !(KdPitchDebugger
))
1163 KdEnableDebuggerWithLock(FALSE
);
1168 /* Otherwise, print the last line */
1169 InbvDisplayString("\r\n");
1172 /* Save the context */
1173 Prcb
->ProcessorState
.ContextFrame
= Context
;
1175 /* FIXME: Support Triage Dump */
1177 /* FIXME: Write the crash dump */
1181 /* Increase recursion count */
1182 KeBugCheckOwnerRecursionCount
++;
1183 if (KeBugCheckOwnerRecursionCount
== 2)
1185 /* Break in the debugger */
1186 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND
);
1188 else if (KeBugCheckOwnerRecursionCount
> 2)
1190 /* Halt execution */
1195 /* Call the Callbacks */
1196 KiDoBugCheckCallbacks();
1198 /* FIXME: Call Watchdog if enabled */
1200 /* Check if we have to reboot */
1203 /* Unload symbols */
1204 DbgUnLoadImageSymbols(NULL
, (PVOID
)MAXULONG_PTR
, 0);
1205 HalReturnToFirmware(HalRebootRoutine
);
1208 /* Attempt to break in the debugger (otherwise halt CPU) */
1209 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND
);
1211 /* Shouldn't get here */
1219 BOOLEAN Handled
= FALSE
;
1220 PKNMI_HANDLER_CALLBACK NmiData
;
1222 /* Parse the list of callbacks */
1223 NmiData
= KiNmiCallbackListHead
;
1226 /* Save if this callback has handled it -- all it takes is one */
1227 Handled
|= NmiData
->Callback(NmiData
->Context
, Handled
);
1228 NmiData
= NmiData
->Next
;
1231 /* Has anyone handled this? */
1235 /* PUBLIC FUNCTIONS **********************************************************/
1242 KeInitializeCrashDumpHeader(IN ULONG Type
,
1245 IN ULONG BufferSize
,
1246 OUT ULONG BufferNeeded OPTIONAL
)
1249 return STATUS_UNSUCCESSFUL
;
1257 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
)
1260 BOOLEAN Status
= FALSE
;
1262 /* Raise IRQL to High */
1263 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1265 /* Check the Current State */
1266 if (CallbackRecord
->State
== BufferInserted
)
1268 /* Reset state and remove from list */
1269 CallbackRecord
->State
= BufferEmpty
;
1270 RemoveEntryList(&CallbackRecord
->Entry
);
1274 /* Lower IRQL and return */
1275 KeLowerIrql(OldIrql
);
1284 KeDeregisterBugCheckReasonCallback(
1285 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
)
1288 BOOLEAN Status
= FALSE
;
1290 /* Raise IRQL to High */
1291 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1293 /* Check the Current State */
1294 if (CallbackRecord
->State
== BufferInserted
)
1296 /* Reset state and remove from list */
1297 CallbackRecord
->State
= BufferEmpty
;
1298 RemoveEntryList(&CallbackRecord
->Entry
);
1302 /* Lower IRQL and return */
1303 KeLowerIrql(OldIrql
);
1312 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
,
1313 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine
,
1316 IN PUCHAR Component
)
1319 BOOLEAN Status
= FALSE
;
1321 /* Raise IRQL to High */
1322 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1324 /* Check the Current State first so we don't double-register */
1325 if (CallbackRecord
->State
== BufferEmpty
)
1327 /* Set the Callback Settings and insert into the list */
1328 CallbackRecord
->Length
= Length
;
1329 CallbackRecord
->Buffer
= Buffer
;
1330 CallbackRecord
->Component
= Component
;
1331 CallbackRecord
->CallbackRoutine
= CallbackRoutine
;
1332 CallbackRecord
->State
= BufferInserted
;
1333 InsertTailList(&KeBugcheckCallbackListHead
, &CallbackRecord
->Entry
);
1337 /* Lower IRQL and return */
1338 KeLowerIrql(OldIrql
);
1347 KeRegisterBugCheckReasonCallback(
1348 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
,
1349 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine
,
1350 IN KBUGCHECK_CALLBACK_REASON Reason
,
1351 IN PUCHAR Component
)
1354 BOOLEAN Status
= FALSE
;
1356 /* Raise IRQL to High */
1357 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1359 /* Check the Current State first so we don't double-register */
1360 if (CallbackRecord
->State
== BufferEmpty
)
1362 /* Set the Callback Settings and insert into the list */
1363 CallbackRecord
->Component
= Component
;
1364 CallbackRecord
->CallbackRoutine
= CallbackRoutine
;
1365 CallbackRecord
->State
= BufferInserted
;
1366 CallbackRecord
->Reason
= Reason
;
1367 InsertTailList(&KeBugcheckReasonCallbackListHead
,
1368 &CallbackRecord
->Entry
);
1372 /* Lower IRQL and return */
1373 KeLowerIrql(OldIrql
);
1382 KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine
,
1386 PKNMI_HANDLER_CALLBACK NmiData
, Next
;
1387 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1389 /* Allocate NMI callback data */
1390 NmiData
= ExAllocatePoolWithTag(NonPagedPool
,
1391 sizeof(KNMI_HANDLER_CALLBACK
),
1393 if (!NmiData
) return NULL
;
1395 /* Fill in the information */
1396 NmiData
->Callback
= CallbackRoutine
;
1397 NmiData
->Context
= Context
;
1398 NmiData
->Handle
= NmiData
;
1400 /* Insert it into NMI callback list */
1401 KiAcquireNmiListLock(&OldIrql
);
1402 NmiData
->Next
= KiNmiCallbackListHead
;
1403 Next
= InterlockedCompareExchangePointer((PVOID
*)&KiNmiCallbackListHead
,
1406 ASSERT(Next
== NmiData
->Next
);
1407 KiReleaseNmiListLock(OldIrql
);
1409 /* Return the opaque "handle" */
1410 return NmiData
->Handle
;
1418 KeDeregisterNmiCallback(PVOID Handle
)
1421 return STATUS_UNSUCCESSFUL
;
1429 KeBugCheckEx(IN ULONG BugCheckCode
,
1430 IN ULONG_PTR BugCheckParameter1
,
1431 IN ULONG_PTR BugCheckParameter2
,
1432 IN ULONG_PTR BugCheckParameter3
,
1433 IN ULONG_PTR BugCheckParameter4
)
1435 /* Workaround for Windows Server 2003 Checked PCI Driver issue */
1436 if (!((BugCheckCode
== PCI_BUS_DRIVER_INTERNAL
) &&
1437 (BugCheckParameter1
== 0xDEAD0010)))
1439 /* Call the internal API */
1440 KeBugCheckWithTf(BugCheckCode
,
1454 KeBugCheck(ULONG BugCheckCode
)
1456 /* Call the internal API */
1457 KeBugCheckWithTf(BugCheckCode
, 0, 0, 0, 0, NULL
);
1465 KeEnterKernelDebugger(VOID
)
1467 /* Disable interrupts */
1468 KiHardwareTrigger
= 1;
1471 /* Check the bugcheck count */
1472 if (!InterlockedDecrement((PLONG
)&KeBugCheckCount
))
1474 /* There was only one, is the debugger disabled? */
1475 if (!(KdDebuggerEnabled
) && !(KdPitchDebugger
))
1477 /* Enable the debugger */
1478 KdInitSystem(0, NULL
);
1482 /* Break in the debugger */
1483 KiBugCheckDebugBreak(DBG_STATUS_FATAL
);