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 KiRosPcToUserFileHeader(IN PVOID Pc
,
108 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
110 PVOID ImageBase
, PcBase
= NULL
;
111 PLDR_DATA_TABLE_ENTRY Entry
;
112 PLIST_ENTRY ListHead
, NextEntry
;
115 * We know this is valid because we should only be called after a
116 * succesfull address from RtlWalkFrameChain for UserMode, which
117 * validates everything for us.
119 ListHead
= &KeGetCurrentThread()->
120 Teb
->ProcessEnvironmentBlock
->Ldr
->InLoadOrderModuleList
;
122 /* Set list pointers and make sure it's valid */
123 NextEntry
= ListHead
->Flink
;
127 while (NextEntry
!= ListHead
)
129 /* Get the loader entry */
130 Entry
= CONTAINING_RECORD(NextEntry
,
131 LDR_DATA_TABLE_ENTRY
,
134 /* Move to the next entry */
135 NextEntry
= NextEntry
->Flink
;
136 ImageBase
= Entry
->DllBase
;
138 /* Check if this is the right one */
139 if (((ULONG_PTR
)Pc
>= (ULONG_PTR
)Entry
->DllBase
) &&
140 ((ULONG_PTR
)Pc
< ((ULONG_PTR
)Entry
->DllBase
+ Entry
->SizeOfImage
)))
142 /* Return this entry */
150 /* Return the base address */
156 KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip
,
157 IN ULONG FramesToCapture
,
158 OUT PVOID
*BackTrace
,
159 OUT PULONG BackTraceHash OPTIONAL
)
161 PVOID Frames
[2 * 64];
165 /* Skip a frame for the caller */
168 /* Don't go past the limit */
169 if ((FramesToCapture
+ FramesToSkip
) >= 128) return 0;
171 /* Do the back trace */
172 FrameCount
= RtlWalkFrameChain(Frames
, FramesToCapture
+ FramesToSkip
, 1);
174 /* Make sure we're not skipping all of them */
175 if (FrameCount
<= FramesToSkip
) return 0;
177 /* Loop all the frames */
178 for (i
= 0; i
< FramesToCapture
; i
++)
180 /* Don't go past the limit */
181 if ((FramesToSkip
+ i
) >= FrameCount
) break;
183 /* Save this entry and hash it */
184 BackTrace
[i
] = Frames
[FramesToSkip
+ i
];
185 Hash
+= PtrToUlong(BackTrace
[i
]);
189 if (BackTraceHash
) *BackTraceHash
= Hash
;
191 /* Clear the other entries and return count */
192 RtlFillMemoryUlong(Frames
, 128, 0);
199 KeRosDumpStackFrameArray(IN PULONG_PTR Frames
,
207 /* GCC complaints that it may be used uninitialized */
208 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
211 for (i
= 0; i
< FrameCount
; i
++)
220 /* Get the base for this file */
221 if (Addr
> (ULONG_PTR
)MmHighestUserAddress
)
223 /* We are in kernel */
224 p
= KiPcToFileHeader((PVOID
)Addr
, &LdrEntry
, FALSE
, &InSystem
);
228 /* We are in user land */
229 p
= KiRosPcToUserFileHeader((PVOID
)Addr
, &LdrEntry
);
234 if (!KdbSymPrintAddress((PVOID
)Addr
, NULL
))
239 /* Convert module name to ANSI and print it */
240 KeBugCheckUnicodeToAnsi(&LdrEntry
->BaseDllName
,
243 Addr
-= (ULONG_PTR
)LdrEntry
->DllBase
;
244 DbgPrint("<%s: %p>", AnsiName
, (PVOID
)Addr
);
249 /* Print only the address */
250 DbgPrint("<%p>", (PVOID
)Addr
);
253 /* Go to the next frame */
260 KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL
,
261 IN ULONG FrameCount OPTIONAL
)
263 ULONG_PTR Frames
[32];
264 ULONG RealFrameCount
;
266 /* If the caller didn't ask, assume 32 frames */
267 if (!FrameCount
|| FrameCount
> 32) FrameCount
= 32;
272 KeRosDumpStackFrameArray(Frame
, FrameCount
);
276 /* Get the current frames (skip the two. One for the dumper, one for the caller) */
277 RealFrameCount
= RtlCaptureStackBackTrace(2, FrameCount
, (PVOID
*)Frames
, NULL
);
278 DPRINT1("RealFrameCount =%lu\n", RealFrameCount
);
281 KeRosDumpStackFrameArray(Frames
, RealFrameCount
);
283 /* Count left for user mode? */
284 if (FrameCount
- RealFrameCount
> 0)
286 /* Get the current frames */
287 RealFrameCount
= KeRosCaptureUserStackBackTrace(-1, FrameCount
- RealFrameCount
, (PVOID
*)Frames
, NULL
);
290 KeRosDumpStackFrameArray(Frames
, RealFrameCount
);
297 KeRosDumpTriageForBugZillaReport(VOID
)
300 extern BOOLEAN KiFastSystemCallDisable
, KiSMTProcessorsPresent
;
301 extern ULONG KeI386MachineType
, MxcsrFeatureMask
;
302 extern BOOLEAN Ke386Pae
, Ke386NoExecute
;
304 DbgPrint("ReactOS has crashed! Please go to http://jira.reactos.org/ to file a bug!\n");
305 DbgPrint("\nHardware Information\n");
306 DbgPrint("Processor Architecture: %d\n"
308 "System Call Disabled: %d\n"
311 "MXCsr Feature Mask: %d\n"
318 "Active Processors: %d\n"
319 "Pentium LOCK Bug: %d\n"
320 "Hyperthreading: %d\n"
321 "CPU Manufacturer: %s\n"
329 "BIOS Version: %wZ\n"
330 "Video BIOS Date: %wZ\n"
331 "Video BIOS Version: %wZ\n"
333 KeProcessorArchitecture
,
335 KiFastSystemCallDisable
,
346 KiI386PentiumLockErrataPresent
,
347 KiSMTProcessorsPresent
,
348 KeGetCurrentPrcb()->VendorString
,
350 KeGetCurrentPrcb()->CpuID
,
351 KeGetCurrentPrcb()->CpuType
,
352 KeGetCurrentPrcb()->CpuStep
,
353 KeGetCurrentPrcb()->MHz
,
354 ((PKIPCR
)KeGetPcr())->SecondLevelCacheSize
,
358 &KeRosVideoBiosVersion
,
359 MmNumberOfPhysicalPages
* PAGE_SIZE
);
366 KiInitializeBugCheck(VOID
)
368 PMESSAGE_RESOURCE_DATA BugCheckData
;
369 LDR_RESOURCE_INFO ResourceInfo
;
370 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
372 PLDR_DATA_TABLE_ENTRY LdrEntry
;
374 /* Get the kernel entry */
375 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
,
376 LDR_DATA_TABLE_ENTRY
,
379 /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
380 ResourceInfo
.Type
= 11;
381 ResourceInfo
.Name
= 1;
382 ResourceInfo
.Language
= 9;
385 Status
= LdrFindResource_U(LdrEntry
->DllBase
,
390 /* Make sure it worked */
391 if (NT_SUCCESS(Status
))
393 /* Now actually get a pointer to it */
394 Status
= LdrAccessResource(LdrEntry
->DllBase
,
396 (PVOID
*)&BugCheckData
,
398 if (NT_SUCCESS(Status
)) KiBugCodeMessages
= BugCheckData
;
404 KeGetBugMessageText(IN ULONG BugCheckCode
,
405 OUT PANSI_STRING OutputString OPTIONAL
)
409 ULONG_PTR MessageEntry
;
411 BOOLEAN Result
= FALSE
;
414 /* Make sure we're not bugchecking too early */
415 if (!KiBugCodeMessages
) return Result
;
417 /* Find the message. This code is based on RtlFindMesssage */
418 for (i
= 0; i
< KiBugCodeMessages
->NumberOfBlocks
; i
++)
420 /* Check if the ID Matches */
421 if ((BugCheckCode
>= KiBugCodeMessages
->Blocks
[i
].LowId
) &&
422 (BugCheckCode
<= KiBugCodeMessages
->Blocks
[i
].HighId
))
424 /* Get Offset to Entry */
425 MessageEntry
= KiBugCodeMessages
->Blocks
[i
].OffsetToEntries
+
426 (ULONG_PTR
)KiBugCodeMessages
;
427 IdOffset
= BugCheckCode
- KiBugCodeMessages
->Blocks
[i
].LowId
;
429 /* Get offset to ID */
430 for (j
= 0; j
< IdOffset
; j
++)
432 /* Advance in the Entries */
433 MessageEntry
+= ((PMESSAGE_RESOURCE_ENTRY
)MessageEntry
)->
437 /* Get the final Code */
438 BugCode
= (PCHAR
)((PMESSAGE_RESOURCE_ENTRY
)MessageEntry
)->Text
;
439 Length
= (USHORT
)strlen(BugCode
);
441 /* Handle trailing newlines */
442 while ((Length
> 0) && ((BugCode
[Length
] == '\n') ||
443 (BugCode
[Length
] == '\r') ||
444 (BugCode
[Length
] == ANSI_NULL
)))
446 /* Check if we have a string to return */
447 if (!OutputString
) BugCode
[Length
] = ANSI_NULL
;
451 /* Check if caller wants an output string */
454 /* Return it in the OutputString */
455 OutputString
->Buffer
= BugCode
;
456 OutputString
->Length
= Length
+ 1;
457 OutputString
->MaximumLength
= Length
+ 1;
461 /* Direct Output to Screen */
462 InbvDisplayString(BugCode
);
463 InbvDisplayString("\r");
472 /* Return the result */
478 KiDoBugCheckCallbacks(VOID
)
480 PKBUGCHECK_CALLBACK_RECORD CurrentRecord
;
481 PLIST_ENTRY ListHead
, NextEntry
, LastEntry
;
484 /* First make sure that the list is Initialized... it might not be */
485 ListHead
= &KeBugcheckCallbackListHead
;
486 if ((ListHead
->Flink
) && (ListHead
->Blink
))
489 LastEntry
= ListHead
;
490 NextEntry
= ListHead
->Flink
;
491 while (NextEntry
!= ListHead
)
494 CurrentRecord
= CONTAINING_RECORD(NextEntry
,
495 KBUGCHECK_CALLBACK_RECORD
,
499 if (CurrentRecord
->Entry
.Blink
!= LastEntry
) return;
500 Checksum
= (ULONG_PTR
)CurrentRecord
->CallbackRoutine
;
501 Checksum
+= (ULONG_PTR
)CurrentRecord
->Buffer
;
502 Checksum
+= (ULONG_PTR
)CurrentRecord
->Length
;
503 Checksum
+= (ULONG_PTR
)CurrentRecord
->Component
;
505 /* Make sure it's inserted and valitdated */
506 if ((CurrentRecord
->State
== BufferInserted
) &&
507 (CurrentRecord
->Checksum
== Checksum
))
509 /* Call the routine */
510 CurrentRecord
->State
= BufferStarted
;
511 (CurrentRecord
->CallbackRoutine
)(CurrentRecord
->Buffer
,
512 CurrentRecord
->Length
);
513 CurrentRecord
->State
= BufferFinished
;
516 /* Go to the next entry */
517 LastEntry
= NextEntry
;
518 NextEntry
= NextEntry
->Flink
;
525 KiBugCheckDebugBreak(IN ULONG StatusCode
)
528 * Wrap this in SEH so we don't crash if
529 * there is no debugger or if it disconnected
535 DbgBreakPointWithStatus(StatusCode
);
537 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
539 /* No debugger, halt the CPU */
544 /* Break again if this wasn't first try */
545 if (StatusCode
!= DBG_STATUS_BUGCHECK_FIRST
) goto DoBreak
;
550 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode
,
558 /* Set length and normalize it */
559 i
= Unicode
->Length
/ sizeof(WCHAR
);
560 i
= min(i
, Length
- 1);
562 /* Set source and destination, and copy */
563 pw
= Unicode
->Buffer
;
565 while (i
--) *p
++ = (CHAR
)*pw
++;
567 /* Null terminate and return */
574 KiDumpParameterImages(IN PCHAR Message
,
575 IN PULONG_PTR Parameters
,
576 IN ULONG ParameterCount
,
577 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine
)
581 PLDR_DATA_TABLE_ENTRY LdrEntry
;
583 PUNICODE_STRING DriverName
;
585 PIMAGE_NT_HEADERS NtHeader
;
587 BOOLEAN FirstRun
= TRUE
;
589 /* Loop parameters */
590 for (i
= 0; i
< ParameterCount
; i
++)
592 /* Get the base for this parameter */
593 ImageBase
= KiPcToFileHeader((PVOID
)Parameters
[i
],
599 /* FIXME: Add code to check for unloaded drivers */
600 DPRINT1("Potentially unloaded driver!\n");
605 /* Get the NT Headers and Timestamp */
606 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
607 TimeStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
609 /* Convert the driver name */
610 DriverName
= &LdrEntry
->BaseDllName
;
611 ConversionRoutine(&LdrEntry
->BaseDllName
,
616 /* Format driver name */
618 "%s** %12s - Address %p base at %p, DateStamp %08lx\r\n",
619 FirstRun
? "\r\n*":"*",
621 (PVOID
)Parameters
[i
],
625 /* Check if we only had one parameter */
626 if (ParameterCount
<= 1)
628 /* Then just save the name */
629 KiBugCheckDriver
= DriverName
;
633 /* Otherwise, display the message */
634 InbvDisplayString(Message
);
644 KiDisplayBlueScreen(IN ULONG MessageId
,
645 IN BOOLEAN IsHardError
,
646 IN PCHAR HardErrCaption OPTIONAL
,
647 IN PCHAR HardErrMessage OPTIONAL
,
652 /* Check if bootvid is installed */
653 if (InbvIsBootDriverInstalled())
655 /* Acquire ownership and reset the display */
656 InbvAcquireDisplayOwnership();
659 /* Display blue screen */
660 InbvSolidColorFill(0, 0, 639, 479, 4);
661 InbvSetTextColor(15);
662 InbvInstallDisplayStringFilter(NULL
);
663 InbvEnableDisplayString(TRUE
);
664 InbvSetScrollRegion(0, 0, 639, 479);
667 /* Check if this is a hard error */
670 /* Display caption and message */
671 if (HardErrCaption
) InbvDisplayString(HardErrCaption
);
672 if (HardErrMessage
) InbvDisplayString(HardErrMessage
);
675 /* Begin the display */
676 InbvDisplayString("\r\n");
678 /* Print out initial message */
679 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO
, NULL
);
680 InbvDisplayString("\r\n\r\n");
682 /* Check if we have a driver */
683 if (KiBugCheckDriver
)
685 /* Print out into to driver name */
686 KeGetBugMessageText(BUGCODE_ID_DRIVER
, NULL
);
688 /* Convert and print out driver name */
689 KeBugCheckUnicodeToAnsi(KiBugCheckDriver
, AnsiName
, sizeof(AnsiName
));
690 InbvDisplayString(" ");
691 InbvDisplayString(AnsiName
);
692 InbvDisplayString("\r\n\r\n");
695 /* Check if this is the generic message */
696 if (MessageId
== BUGCODE_PSS_MESSAGE
)
698 /* It is, so get the bug code string as well */
699 KeGetBugMessageText((ULONG
)KiBugCheckData
[0], NULL
);
700 InbvDisplayString("\r\n\r\n");
703 /* Print second introduction message */
704 KeGetBugMessageText(PSS_MESSAGE_INTRO
, NULL
);
705 InbvDisplayString("\r\n\r\n");
707 /* Get the bug code string */
708 KeGetBugMessageText(MessageId
, NULL
);
709 InbvDisplayString("\r\n\r\n");
711 /* Print message for technical information */
712 KeGetBugMessageText(BUGCHECK_TECH_INFO
, NULL
);
714 /* Show the technical Data */
716 "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
718 (PVOID
)KiBugCheckData
[1],
719 (PVOID
)KiBugCheckData
[2],
720 (PVOID
)KiBugCheckData
[3],
721 (PVOID
)KiBugCheckData
[4]);
722 InbvDisplayString(AnsiName
);
724 /* Check if we have a driver*/
725 if (KiBugCheckDriver
)
727 /* Display technical driver data */
728 InbvDisplayString(Message
);
732 /* Dump parameter information */
733 KiDumpParameterImages(Message
,
734 (PVOID
)&KiBugCheckData
[1],
736 KeBugCheckUnicodeToAnsi
);
742 KeBugCheckWithTf(IN ULONG BugCheckCode
,
743 IN ULONG_PTR BugCheckParameter1
,
744 IN ULONG_PTR BugCheckParameter2
,
745 IN ULONG_PTR BugCheckParameter3
,
746 IN ULONG_PTR BugCheckParameter4
,
747 IN PKTRAP_FRAME TrapFrame
)
749 PKPRCB Prcb
= KeGetCurrentPrcb();
753 BOOLEAN IsSystem
, IsHardError
= FALSE
, Reboot
= FALSE
;
754 PCHAR HardErrCaption
= NULL
, HardErrMessage
= NULL
;
755 PVOID Pc
= NULL
, Memory
;
757 PLDR_DATA_TABLE_ENTRY LdrEntry
;
758 PULONG_PTR HardErrorParameters
;
764 /* Set active bugcheck */
765 KeBugCheckActive
= TRUE
;
766 KiBugCheckDriver
= NULL
;
768 /* Check if this is power failure simulation */
769 if (BugCheckCode
== POWER_FAILURE_SIMULATE
)
771 /* Call the Callbacks and reboot */
772 KiDoBugCheckCallbacks();
773 HalReturnToFirmware(HalRebootRoutine
);
776 /* Save the IRQL and set hardware trigger */
777 Prcb
->DebuggerSavedIRQL
= KeGetCurrentIrql();
778 InterlockedIncrement((PLONG
)&KiHardwareTrigger
);
780 /* Capture the CPU Context */
781 RtlCaptureContext(&Prcb
->ProcessorState
.ContextFrame
);
782 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
783 Context
= Prcb
->ProcessorState
.ContextFrame
;
785 /* FIXME: Call the Watchdog if it's registered */
787 /* Check which bugcode this is */
788 switch (BugCheckCode
)
790 /* These bug checks already have detailed messages, keep them */
791 case UNEXPECTED_KERNEL_MODE_TRAP
:
792 case DRIVER_CORRUPTED_EXPOOL
:
793 case ACPI_BIOS_ERROR
:
794 case ACPI_BIOS_FATAL_ERROR
:
795 case THREAD_STUCK_IN_DEVICE_DRIVER
:
797 case FAT_FILE_SYSTEM
:
798 case NO_MORE_SYSTEM_PTES
:
799 case INACCESSIBLE_BOOT_DEVICE
:
801 /* Keep the same code */
802 MessageId
= BugCheckCode
;
805 /* Check if this is a kernel-mode exception */
806 case KERNEL_MODE_EXCEPTION_NOT_HANDLED
:
807 case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED
:
808 case KMODE_EXCEPTION_NOT_HANDLED
:
810 /* Use the generic text message */
811 MessageId
= KMODE_EXCEPTION_NOT_HANDLED
;
814 /* File-system errors */
815 case NTFS_FILE_SYSTEM
:
817 /* Use the generic message for FAT */
818 MessageId
= FAT_FILE_SYSTEM
;
821 /* Check if this is a coruption of the Mm's Pool */
822 case DRIVER_CORRUPTED_MMPOOL
:
824 /* Use generic corruption message */
825 MessageId
= DRIVER_CORRUPTED_EXPOOL
;
828 /* Check if this is a signature check failure */
829 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
:
831 /* Use the generic corruption message */
832 MessageId
= BUGCODE_PSS_MESSAGE_SIGNATURE
;
835 /* All other codes */
838 /* Use the default bugcheck message */
839 MessageId
= BUGCODE_PSS_MESSAGE
;
843 /* Save bugcheck data */
844 KiBugCheckData
[0] = BugCheckCode
;
845 KiBugCheckData
[1] = BugCheckParameter1
;
846 KiBugCheckData
[2] = BugCheckParameter2
;
847 KiBugCheckData
[3] = BugCheckParameter3
;
848 KiBugCheckData
[4] = BugCheckParameter4
;
850 /* Now check what bugcheck this is */
851 switch (BugCheckCode
)
853 /* Invalid access to R/O memory or Unhandled KM Exception */
854 case KERNEL_MODE_EXCEPTION_NOT_HANDLED
:
855 case ATTEMPTED_WRITE_TO_READONLY_MEMORY
:
856 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY
:
858 /* Check if we have a trap frame */
861 /* Use parameter 3 as a trap frame, if it exists */
862 if (BugCheckParameter3
) TrapFrame
= (PVOID
)BugCheckParameter3
;
865 /* Check if we got one now and if we need to get the Program Counter */
867 (BugCheckCode
!= KERNEL_MODE_EXCEPTION_NOT_HANDLED
))
869 /* Get the Program Counter */
870 Pc
= (PVOID
)KeGetTrapFramePc(TrapFrame
);
875 case IRQL_NOT_LESS_OR_EQUAL
:
878 * The NT kernel has 3 special sections:
879 * MISYSPTE, POOLMI and POOLCODE. The bug check code can
880 * determine in which of these sections this bugcode happened
881 * and provide a more detailed analysis. For now, we don't.
884 /* Program Counter is in parameter 4 */
885 Pc
= (PVOID
)BugCheckParameter4
;
887 /* Get the driver base */
888 DriverBase
= KiPcToFileHeader(Pc
,
895 * The error happened inside the kernel or HAL.
896 * Get the memory address that was being referenced.
898 Memory
= (PVOID
)BugCheckParameter1
;
900 /* Find to which driver it belongs */
901 DriverBase
= KiPcToFileHeader(Memory
,
907 /* Get the driver name and update the bug code */
908 KiBugCheckDriver
= &LdrEntry
->BaseDllName
;
909 KiBugCheckData
[0] = DRIVER_PORTION_MUST_BE_NONPAGED
;
913 /* Find the driver that unloaded at this address */
914 KiBugCheckDriver
= NULL
; // FIXME: ROS can't locate
916 /* Check if the cause was an unloaded driver */
917 if (KiBugCheckDriver
)
919 /* Update bug check code */
921 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD
;
927 /* Update the bug check code */
928 KiBugCheckData
[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL
;
931 /* Clear Pc so we don't look it up later */
936 case FATAL_UNHANDLED_HARD_ERROR
:
938 /* Copy bug check data from hard error */
939 HardErrorParameters
= (PULONG_PTR
)BugCheckParameter2
;
940 KiBugCheckData
[0] = BugCheckParameter1
;
941 KiBugCheckData
[1] = HardErrorParameters
[0];
942 KiBugCheckData
[2] = HardErrorParameters
[1];
943 KiBugCheckData
[3] = HardErrorParameters
[2];
944 KiBugCheckData
[4] = HardErrorParameters
[3];
946 /* Remember that this is hard error and set the caption/message */
948 HardErrCaption
= (PCHAR
)BugCheckParameter3
;
949 HardErrMessage
= (PCHAR
)BugCheckParameter4
;
953 case PAGE_FAULT_IN_NONPAGED_AREA
:
955 /* Assume no driver */
958 /* Check if we have a trap frame */
961 /* We don't, use parameter 3 if possible */
962 if (BugCheckParameter3
) TrapFrame
= (PVOID
)BugCheckParameter3
;
965 /* Check if we have a frame now */
968 /* Get the Program Counter */
969 Pc
= (PVOID
)KeGetTrapFramePc(TrapFrame
);
970 KiBugCheckData
[3] = (ULONG_PTR
)Pc
;
972 /* Find out if was in the kernel or drivers */
973 DriverBase
= KiPcToFileHeader(Pc
,
980 /* Can't blame a driver, assume system */
984 /* FIXME: Check for session pool in addition to special pool */
986 /* Special pool has its own bug check codes */
987 if (MmIsSpecialPoolAddress((PVOID
)BugCheckParameter1
))
989 if (MmIsSpecialPoolAddressFree((PVOID
)BugCheckParameter1
))
991 KiBugCheckData
[0] = IsSystem
992 ? PAGE_FAULT_IN_FREED_SPECIAL_POOL
993 : DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL
;
997 KiBugCheckData
[0] = IsSystem
998 ? PAGE_FAULT_BEYOND_END_OF_ALLOCATION
999 : DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION
;
1002 else if (!DriverBase
)
1004 /* Find the driver that unloaded at this address */
1005 KiBugCheckDriver
= NULL
; // FIXME: ROS can't locate
1007 /* Check if the cause was an unloaded driver */
1008 if (KiBugCheckDriver
)
1011 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS
;
1016 /* Check if the driver forgot to unlock pages */
1017 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS
:
1019 /* Program Counter is in parameter 1 */
1020 Pc
= (PVOID
)BugCheckParameter1
;
1023 /* Check if the driver consumed too many PTEs */
1024 case DRIVER_USED_EXCESSIVE_PTES
:
1026 /* Loader entry is in parameter 1 */
1027 LdrEntry
= (PVOID
)BugCheckParameter1
;
1028 KiBugCheckDriver
= &LdrEntry
->BaseDllName
;
1031 /* Check if the driver has a stuck thread */
1032 case THREAD_STUCK_IN_DEVICE_DRIVER
:
1034 /* The name is in Parameter 3 */
1035 KiBugCheckDriver
= (PVOID
)BugCheckParameter3
;
1043 /* Do we have a driver name? */
1044 if (KiBugCheckDriver
)
1046 /* Convert it to ANSI */
1047 KeBugCheckUnicodeToAnsi(KiBugCheckDriver
, AnsiName
, sizeof(AnsiName
));
1051 /* Do we have a Program Counter? */
1054 /* Dump image name */
1055 KiDumpParameterImages(AnsiName
,
1058 KeBugCheckUnicodeToAnsi
);
1062 /* Check if we need to save the context for KD */
1064 if (!KdPitchDebugger
) KdDebuggerDataBlock
.SavedContext
= (ULONG_PTR
)&Context
;
1067 /* Check if a debugger is connected */
1068 if ((BugCheckCode
!= MANUALLY_INITIATED_CRASH
) && (KdDebuggerEnabled
))
1070 /* Crash on the debugger console */
1071 DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
1072 " (0x%p,0x%p,0x%p,0x%p)\n\n",
1079 /* Check if the debugger isn't currently connected */
1080 if (!KdDebuggerNotPresent
)
1082 /* Check if we have a driver to blame */
1083 if (KiBugCheckDriver
)
1086 DbgPrint("Driver at fault: %s.\n", AnsiName
);
1089 /* Check if this was a hard error */
1092 /* Print caption and message */
1093 if (HardErrCaption
) DbgPrint(HardErrCaption
);
1094 if (HardErrMessage
) DbgPrint(HardErrMessage
);
1097 /* Break in the debugger */
1098 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST
);
1104 * Ok, so debugging is enabled, but KDBG isn't there.
1105 * We'll manually dump the stack for the user.
1107 KeRosDumpStackFrames(NULL
, 0);
1109 /* ROS HACK 2: Generate something useful for Bugzilla */
1110 KeRosDumpTriageForBugZillaReport();
1114 /* Raise IRQL to HIGH_LEVEL */
1116 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1118 /* Avoid recursion */
1119 if (!InterlockedDecrement((PLONG
)&KeBugCheckCount
))
1122 /* Set CPU that is bug checking now */
1123 KeBugCheckOwner
= Prcb
->Number
;
1125 /* Freeze the other CPUs */
1126 for (i
= 0; i
< KeNumberProcessors
; i
++)
1128 if (i
!= (LONG
)KeGetCurrentProcessorNumber())
1130 /* Send the IPI and give them one second to catch up */
1131 KiIpiSend(1 << i
, IPI_FREEZE
);
1132 KeStallExecutionProcessor(1000000);
1137 /* Display the BSOD */
1138 KiDisplayBlueScreen(MessageId
,
1144 /* Check if the debugger is disabled but we can enable it */
1145 if (!(KdDebuggerEnabled
) && !(KdPitchDebugger
))
1149 KdEnableDebuggerWithLock(FALSE
);
1154 /* Otherwise, print the last line */
1155 InbvDisplayString("\r\n");
1158 /* Save the context */
1159 Prcb
->ProcessorState
.ContextFrame
= Context
;
1161 /* FIXME: Support Triage Dump */
1163 /* FIXME: Write the crash dump */
1167 /* Increase recursion count */
1168 KeBugCheckOwnerRecursionCount
++;
1169 if (KeBugCheckOwnerRecursionCount
== 2)
1171 /* Break in the debugger */
1172 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND
);
1174 else if (KeBugCheckOwnerRecursionCount
> 2)
1176 /* Halt execution */
1181 /* Call the Callbacks */
1182 KiDoBugCheckCallbacks();
1184 /* FIXME: Call Watchdog if enabled */
1186 /* Check if we have to reboot */
1189 /* Unload symbols */
1190 DbgUnLoadImageSymbols(NULL
, (PVOID
)MAXULONG_PTR
, 0);
1191 HalReturnToFirmware(HalRebootRoutine
);
1194 /* Attempt to break in the debugger (otherwise halt CPU) */
1195 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND
);
1197 /* Shouldn't get here */
1206 BOOLEAN Handled
= FALSE
;
1207 PKNMI_HANDLER_CALLBACK NmiData
;
1209 /* Parse the list of callbacks */
1210 NmiData
= KiNmiCallbackListHead
;
1213 /* Save if this callback has handled it -- all it takes is one */
1214 Handled
|= NmiData
->Callback(NmiData
->Context
, Handled
);
1215 NmiData
= NmiData
->Next
;
1218 /* Has anyone handled this? */
1222 /* PUBLIC FUNCTIONS **********************************************************/
1229 KeInitializeCrashDumpHeader(IN ULONG Type
,
1232 IN ULONG BufferSize
,
1233 OUT ULONG BufferNeeded OPTIONAL
)
1236 return STATUS_UNSUCCESSFUL
;
1244 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
)
1247 BOOLEAN Status
= FALSE
;
1249 /* Raise IRQL to High */
1250 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1252 /* Check the Current State */
1253 if (CallbackRecord
->State
== BufferInserted
)
1255 /* Reset state and remove from list */
1256 CallbackRecord
->State
= BufferEmpty
;
1257 RemoveEntryList(&CallbackRecord
->Entry
);
1261 /* Lower IRQL and return */
1262 KeLowerIrql(OldIrql
);
1271 KeDeregisterBugCheckReasonCallback(
1272 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
)
1275 BOOLEAN Status
= FALSE
;
1277 /* Raise IRQL to High */
1278 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1280 /* Check the Current State */
1281 if (CallbackRecord
->State
== BufferInserted
)
1283 /* Reset state and remove from list */
1284 CallbackRecord
->State
= BufferEmpty
;
1285 RemoveEntryList(&CallbackRecord
->Entry
);
1289 /* Lower IRQL and return */
1290 KeLowerIrql(OldIrql
);
1299 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
,
1300 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine
,
1303 IN PUCHAR Component
)
1306 BOOLEAN Status
= FALSE
;
1308 /* Raise IRQL to High */
1309 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1311 /* Check the Current State first so we don't double-register */
1312 if (CallbackRecord
->State
== BufferEmpty
)
1314 /* Set the Callback Settings and insert into the list */
1315 CallbackRecord
->Length
= Length
;
1316 CallbackRecord
->Buffer
= Buffer
;
1317 CallbackRecord
->Component
= Component
;
1318 CallbackRecord
->CallbackRoutine
= CallbackRoutine
;
1319 CallbackRecord
->State
= BufferInserted
;
1320 InsertTailList(&KeBugcheckCallbackListHead
, &CallbackRecord
->Entry
);
1324 /* Lower IRQL and return */
1325 KeLowerIrql(OldIrql
);
1334 KeRegisterBugCheckReasonCallback(
1335 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
,
1336 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine
,
1337 IN KBUGCHECK_CALLBACK_REASON Reason
,
1338 IN PUCHAR Component
)
1341 BOOLEAN Status
= FALSE
;
1343 /* Raise IRQL to High */
1344 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1346 /* Check the Current State first so we don't double-register */
1347 if (CallbackRecord
->State
== BufferEmpty
)
1349 /* Set the Callback Settings and insert into the list */
1350 CallbackRecord
->Component
= Component
;
1351 CallbackRecord
->CallbackRoutine
= CallbackRoutine
;
1352 CallbackRecord
->State
= BufferInserted
;
1353 CallbackRecord
->Reason
= Reason
;
1354 InsertTailList(&KeBugcheckReasonCallbackListHead
,
1355 &CallbackRecord
->Entry
);
1359 /* Lower IRQL and return */
1360 KeLowerIrql(OldIrql
);
1369 KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine
,
1373 PKNMI_HANDLER_CALLBACK NmiData
, Next
;
1374 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1376 /* Allocate NMI callback data */
1377 NmiData
= ExAllocatePoolWithTag(NonPagedPool
,
1378 sizeof(KNMI_HANDLER_CALLBACK
),
1380 if (!NmiData
) return NULL
;
1382 /* Fill in the information */
1383 NmiData
->Callback
= CallbackRoutine
;
1384 NmiData
->Context
= Context
;
1385 NmiData
->Handle
= NmiData
;
1387 /* Insert it into NMI callback list */
1388 KiAcquireNmiListLock(&OldIrql
);
1389 NmiData
->Next
= KiNmiCallbackListHead
;
1390 Next
= InterlockedCompareExchangePointer((PVOID
*)&KiNmiCallbackListHead
,
1393 ASSERT(Next
== NmiData
->Next
);
1394 KiReleaseNmiListLock(OldIrql
);
1396 /* Return the opaque "handle" */
1397 return NmiData
->Handle
;
1405 KeDeregisterNmiCallback(PVOID Handle
)
1408 return STATUS_UNSUCCESSFUL
;
1416 KeBugCheckEx(IN ULONG BugCheckCode
,
1417 IN ULONG_PTR BugCheckParameter1
,
1418 IN ULONG_PTR BugCheckParameter2
,
1419 IN ULONG_PTR BugCheckParameter3
,
1420 IN ULONG_PTR BugCheckParameter4
)
1422 /* Call the internal API */
1423 KeBugCheckWithTf(BugCheckCode
,
1436 KeBugCheck(ULONG BugCheckCode
)
1438 /* Call the internal API */
1439 KeBugCheckWithTf(BugCheckCode
, 0, 0, 0, 0, NULL
);
1447 KeEnterKernelDebugger(VOID
)
1449 /* Disable interrupts */
1450 KiHardwareTrigger
= 1;
1453 /* Check the bugcheck count */
1454 if (!InterlockedDecrement((PLONG
)&KeBugCheckCount
))
1456 /* There was only one, is the debugger disabled? */
1457 if (!(KdDebuggerEnabled
) && !(KdPitchDebugger
))
1459 /* Enable the debugger */
1460 KdInitSystem(0, NULL
);
1464 /* Break in the debugger */
1465 KiBugCheckDebugBreak(DBG_STATUS_FATAL
);