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];
32 PKNMI_HANDLER_CALLBACK KiNmiCallbackListHead
= NULL
;
33 KSPIN_LOCK KiNmiCallbackListLock
;
34 #define TAG_KNMI 'IMNK'
36 /* Bugzilla Reporting */
37 UNICODE_STRING KeRosProcessorName
, KeRosBiosDate
, KeRosBiosVersion
;
38 UNICODE_STRING KeRosVideoBiosDate
, KeRosVideoBiosVersion
;
40 /* PRIVATE FUNCTIONS *********************************************************/
44 KiPcToFileHeader(IN PVOID Pc
,
45 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
,
46 IN BOOLEAN DriversOnly
,
47 OUT PBOOLEAN InKernel
)
50 PVOID ImageBase
, PcBase
= NULL
;
51 PLDR_DATA_TABLE_ENTRY Entry
;
52 PLIST_ENTRY ListHead
, NextEntry
;
54 /* Check which list we should use */
55 ListHead
= (KeLoaderBlock
) ? &KeLoaderBlock
->LoadOrderListHead
:
61 /* Set list pointers and make sure it's valid */
62 NextEntry
= ListHead
->Flink
;
66 while (NextEntry
!= ListHead
)
71 /* Check if this is a kernel entry and we only want drivers */
72 if ((i
<= 2) && (DriversOnly
!= FALSE
))
75 NextEntry
= NextEntry
->Flink
;
79 /* Get the loader entry */
80 Entry
= CONTAINING_RECORD(NextEntry
,
84 /* Move to the next entry */
85 NextEntry
= NextEntry
->Flink
;
86 ImageBase
= Entry
->DllBase
;
88 /* Check if this is the right one */
89 if (((ULONG_PTR
)Pc
>= (ULONG_PTR
)Entry
->DllBase
) &&
90 ((ULONG_PTR
)Pc
< ((ULONG_PTR
)Entry
->DllBase
+ Entry
->SizeOfImage
)))
92 /* Return this entry */
96 /* Check if this was a kernel or HAL entry */
97 if (i
<= 2) *InKernel
= TRUE
;
103 /* Return the base address */
109 KiRosPcToUserFileHeader(IN PVOID Pc
,
110 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
)
112 PVOID ImageBase
, PcBase
= NULL
;
113 PLDR_DATA_TABLE_ENTRY Entry
;
114 PLIST_ENTRY ListHead
, NextEntry
;
117 * We know this is valid because we should only be called after a
118 * succesfull address from RtlWalkFrameChain for UserMode, which
119 * validates everything for us.
121 ListHead
= &KeGetCurrentThread()->
122 Teb
->ProcessEnvironmentBlock
->Ldr
->InLoadOrderModuleList
;
124 /* Set list pointers and make sure it's valid */
125 NextEntry
= ListHead
->Flink
;
129 while (NextEntry
!= ListHead
)
131 /* Get the loader entry */
132 Entry
= CONTAINING_RECORD(NextEntry
,
133 LDR_DATA_TABLE_ENTRY
,
136 /* Move to the next entry */
137 NextEntry
= NextEntry
->Flink
;
138 ImageBase
= Entry
->DllBase
;
140 /* Check if this is the right one */
141 if (((ULONG_PTR
)Pc
>= (ULONG_PTR
)Entry
->DllBase
) &&
142 ((ULONG_PTR
)Pc
< ((ULONG_PTR
)Entry
->DllBase
+ Entry
->SizeOfImage
)))
144 /* Return this entry */
152 /* Return the base address */
158 KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip
,
159 IN ULONG FramesToCapture
,
160 OUT PVOID
*BackTrace
,
161 OUT PULONG BackTraceHash OPTIONAL
)
163 PVOID Frames
[2 * 64];
167 /* Skip a frame for the caller */
170 /* Don't go past the limit */
171 if ((FramesToCapture
+ FramesToSkip
) >= 128) return 0;
173 /* Do the back trace */
174 FrameCount
= RtlWalkFrameChain(Frames
, FramesToCapture
+ FramesToSkip
, 1);
176 /* Make sure we're not skipping all of them */
177 if (FrameCount
<= FramesToSkip
) return 0;
179 /* Loop all the frames */
180 for (i
= 0; i
< FramesToCapture
; i
++)
182 /* Don't go past the limit */
183 if ((FramesToSkip
+ i
) >= FrameCount
) break;
185 /* Save this entry and hash it */
186 BackTrace
[i
] = Frames
[FramesToSkip
+ i
];
187 Hash
+= PtrToUlong(BackTrace
[i
]);
191 if (BackTraceHash
) *BackTraceHash
= Hash
;
193 /* Clear the other entries and return count */
194 RtlFillMemoryUlong(Frames
, 128, 0);
201 KeRosDumpStackFrameArray(IN PULONG_PTR Frames
,
209 /* GCC complaints that it may be used uninitialized */
210 PLDR_DATA_TABLE_ENTRY LdrEntry
= NULL
;
213 for (i
= 0; i
< FrameCount
; i
++)
222 /* Get the base for this file */
223 if (Addr
> (ULONG_PTR
)MmHighestUserAddress
)
225 /* We are in kernel */
226 p
= KiPcToFileHeader((PVOID
)Addr
, &LdrEntry
, FALSE
, &InSystem
);
230 /* We are in user land */
231 p
= KiRosPcToUserFileHeader((PVOID
)Addr
, &LdrEntry
);
236 if (!KdbSymPrintAddress((PVOID
)Addr
, NULL
))
241 /* Convert module name to ANSI and print it */
242 KeBugCheckUnicodeToAnsi(&LdrEntry
->BaseDllName
,
245 Addr
-= (ULONG_PTR
)LdrEntry
->DllBase
;
246 DbgPrint("<%s: %p>", AnsiName
, (PVOID
)Addr
);
251 /* Print only the address */
252 DbgPrint("<%p>", (PVOID
)Addr
);
255 /* Go to the next frame */
262 KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL
,
263 IN ULONG FrameCount OPTIONAL
)
265 ULONG_PTR Frames
[32];
266 ULONG RealFrameCount
;
268 /* If the caller didn't ask, assume 32 frames */
269 if (!FrameCount
|| FrameCount
> 32) FrameCount
= 32;
274 KeRosDumpStackFrameArray(Frame
, FrameCount
);
278 /* Get the current frames (skip the two. One for the dumper, one for the caller) */
279 RealFrameCount
= RtlCaptureStackBackTrace(2, FrameCount
, (PVOID
*)Frames
, NULL
);
280 DPRINT1("RealFrameCount =%lu\n", RealFrameCount
);
283 KeRosDumpStackFrameArray(Frames
, RealFrameCount
);
285 /* Count left for user mode? */
286 if (FrameCount
- RealFrameCount
> 0)
288 /* Get the current frames */
289 RealFrameCount
= KeRosCaptureUserStackBackTrace(-1, FrameCount
- RealFrameCount
, (PVOID
*)Frames
, NULL
);
292 KeRosDumpStackFrameArray(Frames
, RealFrameCount
);
299 KeRosDumpTriageForBugZillaReport(VOID
)
302 extern BOOLEAN KiFastSystemCallDisable
, KiSMTProcessorsPresent
;
303 extern ULONG KeI386MachineType
, MxcsrFeatureMask
;
304 extern BOOLEAN Ke386Pae
, Ke386NoExecute
;
306 DbgPrint("ReactOS has crashed! Please go to http://jira.reactos.org/ to file a bug!\n");
307 DbgPrint("\nHardware Information\n");
308 DbgPrint("Processor Architecture: %d\n"
310 "System Call Disabled: %d\n"
313 "MXCsr Feature Mask: %d\n"
320 "Active Processors: %d\n"
321 "Pentium LOCK Bug: %d\n"
322 "Hyperthreading: %d\n"
323 "CPU Manufacturer: %s\n"
331 "BIOS Version: %wZ\n"
332 "Video BIOS Date: %wZ\n"
333 "Video BIOS Version: %wZ\n"
335 KeProcessorArchitecture
,
337 KiFastSystemCallDisable
,
348 KiI386PentiumLockErrataPresent
,
349 KiSMTProcessorsPresent
,
350 KeGetCurrentPrcb()->VendorString
,
352 KeGetCurrentPrcb()->CpuID
,
353 KeGetCurrentPrcb()->CpuType
,
354 KeGetCurrentPrcb()->CpuStep
,
355 KeGetCurrentPrcb()->MHz
,
356 ((PKIPCR
)KeGetPcr())->SecondLevelCacheSize
,
360 &KeRosVideoBiosVersion
,
361 MmNumberOfPhysicalPages
* PAGE_SIZE
);
368 KiInitializeBugCheck(VOID
)
370 PMESSAGE_RESOURCE_DATA BugCheckData
;
371 LDR_RESOURCE_INFO ResourceInfo
;
372 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
374 PLDR_DATA_TABLE_ENTRY LdrEntry
;
376 /* Get the kernel entry */
377 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
,
378 LDR_DATA_TABLE_ENTRY
,
381 /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
382 ResourceInfo
.Type
= 11;
383 ResourceInfo
.Name
= 1;
384 ResourceInfo
.Language
= 9;
387 Status
= LdrFindResource_U(LdrEntry
->DllBase
,
392 /* Make sure it worked */
393 if (NT_SUCCESS(Status
))
395 /* Now actually get a pointer to it */
396 Status
= LdrAccessResource(LdrEntry
->DllBase
,
398 (PVOID
*)&BugCheckData
,
400 if (NT_SUCCESS(Status
)) KiBugCodeMessages
= BugCheckData
;
406 KeGetBugMessageText(IN ULONG BugCheckCode
,
407 OUT PANSI_STRING OutputString OPTIONAL
)
411 ULONG_PTR MessageEntry
;
413 BOOLEAN Result
= FALSE
;
416 /* Make sure we're not bugchecking too early */
417 if (!KiBugCodeMessages
) return Result
;
419 /* Find the message. This code is based on RtlFindMesssage */
420 for (i
= 0; i
< KiBugCodeMessages
->NumberOfBlocks
; i
++)
422 /* Check if the ID Matches */
423 if ((BugCheckCode
>= KiBugCodeMessages
->Blocks
[i
].LowId
) &&
424 (BugCheckCode
<= KiBugCodeMessages
->Blocks
[i
].HighId
))
426 /* Get Offset to Entry */
427 MessageEntry
= KiBugCodeMessages
->Blocks
[i
].OffsetToEntries
+
428 (ULONG_PTR
)KiBugCodeMessages
;
429 IdOffset
= BugCheckCode
- KiBugCodeMessages
->Blocks
[i
].LowId
;
431 /* Get offset to ID */
432 for (j
= 0; j
< IdOffset
; j
++)
434 /* Advance in the Entries */
435 MessageEntry
+= ((PMESSAGE_RESOURCE_ENTRY
)MessageEntry
)->
439 /* Get the final Code */
440 BugCode
= (PCHAR
)((PMESSAGE_RESOURCE_ENTRY
)MessageEntry
)->Text
;
441 Length
= (USHORT
)strlen(BugCode
);
443 /* Handle trailing newlines */
444 while ((Length
> 0) && ((BugCode
[Length
] == '\n') ||
445 (BugCode
[Length
] == '\r') ||
446 (BugCode
[Length
] == ANSI_NULL
)))
448 /* Check if we have a string to return */
449 if (!OutputString
) BugCode
[Length
] = ANSI_NULL
;
453 /* Check if caller wants an output string */
456 /* Return it in the OutputString */
457 OutputString
->Buffer
= BugCode
;
458 OutputString
->Length
= Length
+ 1;
459 OutputString
->MaximumLength
= Length
+ 1;
463 /* Direct Output to Screen */
464 InbvDisplayString(BugCode
);
465 InbvDisplayString("\r");
474 /* Return the result */
480 KiDoBugCheckCallbacks(VOID
)
482 PKBUGCHECK_CALLBACK_RECORD CurrentRecord
;
483 PLIST_ENTRY ListHead
, NextEntry
, LastEntry
;
486 /* First make sure that the list is Initialized... it might not be */
487 ListHead
= &KeBugcheckCallbackListHead
;
488 if ((ListHead
->Flink
) && (ListHead
->Blink
))
491 LastEntry
= ListHead
;
492 NextEntry
= ListHead
->Flink
;
493 while (NextEntry
!= ListHead
)
496 CurrentRecord
= CONTAINING_RECORD(NextEntry
,
497 KBUGCHECK_CALLBACK_RECORD
,
501 if (CurrentRecord
->Entry
.Blink
!= LastEntry
) return;
502 Checksum
= (ULONG_PTR
)CurrentRecord
->CallbackRoutine
;
503 Checksum
+= (ULONG_PTR
)CurrentRecord
->Buffer
;
504 Checksum
+= (ULONG_PTR
)CurrentRecord
->Length
;
505 Checksum
+= (ULONG_PTR
)CurrentRecord
->Component
;
507 /* Make sure it's inserted and valitdated */
508 if ((CurrentRecord
->State
== BufferInserted
) &&
509 (CurrentRecord
->Checksum
== Checksum
))
511 /* Call the routine */
512 CurrentRecord
->State
= BufferStarted
;
513 (CurrentRecord
->CallbackRoutine
)(CurrentRecord
->Buffer
,
514 CurrentRecord
->Length
);
515 CurrentRecord
->State
= BufferFinished
;
518 /* Go to the next entry */
519 LastEntry
= NextEntry
;
520 NextEntry
= NextEntry
->Flink
;
527 KiBugCheckDebugBreak(IN ULONG StatusCode
)
530 * Wrap this in SEH so we don't crash if
531 * there is no debugger or if it disconnected
537 DbgBreakPointWithStatus(StatusCode
);
539 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
541 /* No debugger, halt the CPU */
546 /* Break again if this wasn't first try */
547 if (StatusCode
!= DBG_STATUS_BUGCHECK_FIRST
) goto DoBreak
;
552 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode
,
560 /* Set length and normalize it */
561 i
= Unicode
->Length
/ sizeof(WCHAR
);
562 i
= min(i
, Length
- 1);
564 /* Set source and destination, and copy */
565 pw
= Unicode
->Buffer
;
567 while (i
--) *p
++ = (CHAR
)*pw
++;
569 /* Null terminate and return */
576 KiDumpParameterImages(IN PCHAR Message
,
577 IN PULONG_PTR Parameters
,
578 IN ULONG ParameterCount
,
579 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine
)
583 PLDR_DATA_TABLE_ENTRY LdrEntry
;
585 PUNICODE_STRING DriverName
;
587 PIMAGE_NT_HEADERS NtHeader
;
589 BOOLEAN FirstRun
= TRUE
;
591 /* Loop parameters */
592 for (i
= 0; i
< ParameterCount
; i
++)
594 /* Get the base for this parameter */
595 ImageBase
= KiPcToFileHeader((PVOID
)Parameters
[i
],
601 /* FIXME: Add code to check for unloaded drivers */
602 DPRINT1("Potentially unloaded driver!\n");
607 /* Get the NT Headers and Timestamp */
608 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
609 TimeStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
611 /* Convert the driver name */
612 DriverName
= &LdrEntry
->BaseDllName
;
613 ConversionRoutine(&LdrEntry
->BaseDllName
,
618 /* Format driver name */
620 "%s** %12s - Address %p base at %p, DateStamp %08lx\r\n",
621 FirstRun
? "\r\n*":"*",
623 (PVOID
)Parameters
[i
],
627 /* Check if we only had one parameter */
628 if (ParameterCount
<= 1)
630 /* Then just save the name */
631 KiBugCheckDriver
= DriverName
;
635 /* Otherwise, display the message */
636 InbvDisplayString(Message
);
646 KiDisplayBlueScreen(IN ULONG MessageId
,
647 IN BOOLEAN IsHardError
,
648 IN PCHAR HardErrCaption OPTIONAL
,
649 IN PCHAR HardErrMessage OPTIONAL
,
654 /* Check if bootvid is installed */
655 if (InbvIsBootDriverInstalled())
657 /* Acquire ownership and reset the display */
658 InbvAcquireDisplayOwnership();
661 /* Display blue screen */
662 InbvSolidColorFill(0, 0, 639, 479, 4);
663 InbvSetTextColor(15);
664 InbvInstallDisplayStringFilter(NULL
);
665 InbvEnableDisplayString(TRUE
);
666 InbvSetScrollRegion(0, 0, 639, 479);
669 /* Check if this is a hard error */
672 /* Display caption and message */
673 if (HardErrCaption
) InbvDisplayString(HardErrCaption
);
674 if (HardErrMessage
) InbvDisplayString(HardErrMessage
);
677 /* Begin the display */
678 InbvDisplayString("\r\n");
680 /* Print out initial message */
681 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO
, NULL
);
682 InbvDisplayString("\r\n\r\n");
684 /* Check if we have a driver */
685 if (KiBugCheckDriver
)
687 /* Print out into to driver name */
688 KeGetBugMessageText(BUGCODE_ID_DRIVER
, NULL
);
690 /* Convert and print out driver name */
691 KeBugCheckUnicodeToAnsi(KiBugCheckDriver
, AnsiName
, sizeof(AnsiName
));
692 InbvDisplayString(" ");
693 InbvDisplayString(AnsiName
);
694 InbvDisplayString("\r\n\r\n");
697 /* Check if this is the generic message */
698 if (MessageId
== BUGCODE_PSS_MESSAGE
)
700 /* It is, so get the bug code string as well */
701 KeGetBugMessageText((ULONG
)KiBugCheckData
[0], NULL
);
702 InbvDisplayString("\r\n\r\n");
705 /* Print second introduction message */
706 KeGetBugMessageText(PSS_MESSAGE_INTRO
, NULL
);
707 InbvDisplayString("\r\n\r\n");
709 /* Get the bug code string */
710 KeGetBugMessageText(MessageId
, NULL
);
711 InbvDisplayString("\r\n\r\n");
713 /* Print message for technical information */
714 KeGetBugMessageText(BUGCHECK_TECH_INFO
, NULL
);
716 /* Show the technical Data */
718 "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
719 (ULONG
)KiBugCheckData
[0],
720 (PVOID
)KiBugCheckData
[1],
721 (PVOID
)KiBugCheckData
[2],
722 (PVOID
)KiBugCheckData
[3],
723 (PVOID
)KiBugCheckData
[4]);
724 InbvDisplayString(AnsiName
);
726 /* Check if we have a driver*/
727 if (KiBugCheckDriver
)
729 /* Display technical driver data */
730 InbvDisplayString(Message
);
734 /* Dump parameter information */
735 KiDumpParameterImages(Message
,
736 (PVOID
)&KiBugCheckData
[1],
738 KeBugCheckUnicodeToAnsi
);
744 KeBugCheckWithTf(IN ULONG BugCheckCode
,
745 IN ULONG_PTR BugCheckParameter1
,
746 IN ULONG_PTR BugCheckParameter2
,
747 IN ULONG_PTR BugCheckParameter3
,
748 IN ULONG_PTR BugCheckParameter4
,
749 IN PKTRAP_FRAME TrapFrame
)
751 PKPRCB Prcb
= KeGetCurrentPrcb();
755 BOOLEAN IsSystem
, IsHardError
= FALSE
, Reboot
= FALSE
;
756 PCHAR HardErrCaption
= NULL
, HardErrMessage
= NULL
;
757 PVOID Pc
= NULL
, Memory
;
759 PLDR_DATA_TABLE_ENTRY LdrEntry
;
760 PULONG_PTR HardErrorParameters
;
766 /* Set active bugcheck */
767 KeBugCheckActive
= TRUE
;
768 KiBugCheckDriver
= NULL
;
770 /* Check if this is power failure simulation */
771 if (BugCheckCode
== POWER_FAILURE_SIMULATE
)
773 /* Call the Callbacks and reboot */
774 KiDoBugCheckCallbacks();
775 HalReturnToFirmware(HalRebootRoutine
);
778 /* Save the IRQL and set hardware trigger */
779 Prcb
->DebuggerSavedIRQL
= KeGetCurrentIrql();
780 InterlockedIncrement((PLONG
)&KiHardwareTrigger
);
782 /* Capture the CPU Context */
783 RtlCaptureContext(&Prcb
->ProcessorState
.ContextFrame
);
784 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
785 Context
= Prcb
->ProcessorState
.ContextFrame
;
787 /* FIXME: Call the Watchdog if it's registered */
789 /* Check which bugcode this is */
790 switch (BugCheckCode
)
792 /* These bug checks already have detailed messages, keep them */
793 case UNEXPECTED_KERNEL_MODE_TRAP
:
794 case DRIVER_CORRUPTED_EXPOOL
:
795 case ACPI_BIOS_ERROR
:
796 case ACPI_BIOS_FATAL_ERROR
:
797 case THREAD_STUCK_IN_DEVICE_DRIVER
:
799 case FAT_FILE_SYSTEM
:
800 case NO_MORE_SYSTEM_PTES
:
801 case INACCESSIBLE_BOOT_DEVICE
:
803 /* Keep the same code */
804 MessageId
= BugCheckCode
;
807 /* Check if this is a kernel-mode exception */
808 case KERNEL_MODE_EXCEPTION_NOT_HANDLED
:
809 case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED
:
810 case KMODE_EXCEPTION_NOT_HANDLED
:
812 /* Use the generic text message */
813 MessageId
= KMODE_EXCEPTION_NOT_HANDLED
;
816 /* File-system errors */
817 case NTFS_FILE_SYSTEM
:
819 /* Use the generic message for FAT */
820 MessageId
= FAT_FILE_SYSTEM
;
823 /* Check if this is a coruption of the Mm's Pool */
824 case DRIVER_CORRUPTED_MMPOOL
:
826 /* Use generic corruption message */
827 MessageId
= DRIVER_CORRUPTED_EXPOOL
;
830 /* Check if this is a signature check failure */
831 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
:
833 /* Use the generic corruption message */
834 MessageId
= BUGCODE_PSS_MESSAGE_SIGNATURE
;
837 /* All other codes */
840 /* Use the default bugcheck message */
841 MessageId
= BUGCODE_PSS_MESSAGE
;
845 /* Save bugcheck data */
846 KiBugCheckData
[0] = BugCheckCode
;
847 KiBugCheckData
[1] = BugCheckParameter1
;
848 KiBugCheckData
[2] = BugCheckParameter2
;
849 KiBugCheckData
[3] = BugCheckParameter3
;
850 KiBugCheckData
[4] = BugCheckParameter4
;
852 /* Now check what bugcheck this is */
853 switch (BugCheckCode
)
855 /* Invalid access to R/O memory or Unhandled KM Exception */
856 case KERNEL_MODE_EXCEPTION_NOT_HANDLED
:
857 case ATTEMPTED_WRITE_TO_READONLY_MEMORY
:
858 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY
:
860 /* Check if we have a trap frame */
863 /* Use parameter 3 as a trap frame, if it exists */
864 if (BugCheckParameter3
) TrapFrame
= (PVOID
)BugCheckParameter3
;
867 /* Check if we got one now and if we need to get the Program Counter */
869 (BugCheckCode
!= KERNEL_MODE_EXCEPTION_NOT_HANDLED
))
871 /* Get the Program Counter */
872 Pc
= (PVOID
)KeGetTrapFramePc(TrapFrame
);
877 case IRQL_NOT_LESS_OR_EQUAL
:
880 * The NT kernel has 3 special sections:
881 * MISYSPTE, POOLMI and POOLCODE. The bug check code can
882 * determine in which of these sections this bugcode happened
883 * and provide a more detailed analysis. For now, we don't.
886 /* Program Counter is in parameter 4 */
887 Pc
= (PVOID
)BugCheckParameter4
;
889 /* Get the driver base */
890 DriverBase
= KiPcToFileHeader(Pc
,
897 * The error happened inside the kernel or HAL.
898 * Get the memory address that was being referenced.
900 Memory
= (PVOID
)BugCheckParameter1
;
902 /* Find to which driver it belongs */
903 DriverBase
= KiPcToFileHeader(Memory
,
909 /* Get the driver name and update the bug code */
910 KiBugCheckDriver
= &LdrEntry
->BaseDllName
;
911 KiBugCheckData
[0] = DRIVER_PORTION_MUST_BE_NONPAGED
;
915 /* Find the driver that unloaded at this address */
916 KiBugCheckDriver
= NULL
; // FIXME: ROS can't locate
918 /* Check if the cause was an unloaded driver */
919 if (KiBugCheckDriver
)
921 /* Update bug check code */
923 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD
;
929 /* Update the bug check code */
930 KiBugCheckData
[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL
;
933 /* Clear Pc so we don't look it up later */
938 case FATAL_UNHANDLED_HARD_ERROR
:
940 /* Copy bug check data from hard error */
941 HardErrorParameters
= (PULONG_PTR
)BugCheckParameter2
;
942 KiBugCheckData
[0] = BugCheckParameter1
;
943 KiBugCheckData
[1] = HardErrorParameters
[0];
944 KiBugCheckData
[2] = HardErrorParameters
[1];
945 KiBugCheckData
[3] = HardErrorParameters
[2];
946 KiBugCheckData
[4] = HardErrorParameters
[3];
948 /* Remember that this is hard error and set the caption/message */
950 HardErrCaption
= (PCHAR
)BugCheckParameter3
;
951 HardErrMessage
= (PCHAR
)BugCheckParameter4
;
955 case PAGE_FAULT_IN_NONPAGED_AREA
:
957 /* Assume no driver */
960 /* Check if we have a trap frame */
963 /* We don't, use parameter 3 if possible */
964 if (BugCheckParameter3
) TrapFrame
= (PVOID
)BugCheckParameter3
;
967 /* Check if we have a frame now */
970 /* Get the Program Counter */
971 Pc
= (PVOID
)KeGetTrapFramePc(TrapFrame
);
972 KiBugCheckData
[3] = (ULONG_PTR
)Pc
;
974 /* Find out if was in the kernel or drivers */
975 DriverBase
= KiPcToFileHeader(Pc
,
982 /* Can't blame a driver, assume system */
986 /* FIXME: Check for session pool in addition to special pool */
988 /* Special pool has its own bug check codes */
989 if (MmIsSpecialPoolAddress((PVOID
)BugCheckParameter1
))
991 if (MmIsSpecialPoolAddressFree((PVOID
)BugCheckParameter1
))
993 KiBugCheckData
[0] = IsSystem
994 ? PAGE_FAULT_IN_FREED_SPECIAL_POOL
995 : DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL
;
999 KiBugCheckData
[0] = IsSystem
1000 ? PAGE_FAULT_BEYOND_END_OF_ALLOCATION
1001 : DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION
;
1004 else if (!DriverBase
)
1006 /* Find the driver that unloaded at this address */
1007 KiBugCheckDriver
= NULL
; // FIXME: ROS can't locate
1009 /* Check if the cause was an unloaded driver */
1010 if (KiBugCheckDriver
)
1013 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS
;
1018 /* Check if the driver forgot to unlock pages */
1019 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS
:
1021 /* Program Counter is in parameter 1 */
1022 Pc
= (PVOID
)BugCheckParameter1
;
1025 /* Check if the driver consumed too many PTEs */
1026 case DRIVER_USED_EXCESSIVE_PTES
:
1028 /* Loader entry is in parameter 1 */
1029 LdrEntry
= (PVOID
)BugCheckParameter1
;
1030 KiBugCheckDriver
= &LdrEntry
->BaseDllName
;
1033 /* Check if the driver has a stuck thread */
1034 case THREAD_STUCK_IN_DEVICE_DRIVER
:
1036 /* The name is in Parameter 3 */
1037 KiBugCheckDriver
= (PVOID
)BugCheckParameter3
;
1045 /* Do we have a driver name? */
1046 if (KiBugCheckDriver
)
1048 /* Convert it to ANSI */
1049 KeBugCheckUnicodeToAnsi(KiBugCheckDriver
, AnsiName
, sizeof(AnsiName
));
1053 /* Do we have a Program Counter? */
1056 /* Dump image name */
1057 KiDumpParameterImages(AnsiName
,
1060 KeBugCheckUnicodeToAnsi
);
1064 /* Check if we need to save the context for KD */
1066 if (!KdPitchDebugger
) KdDebuggerDataBlock
.SavedContext
= (ULONG_PTR
)&Context
;
1069 /* Check if a debugger is connected */
1070 if ((BugCheckCode
!= MANUALLY_INITIATED_CRASH
) && (KdDebuggerEnabled
))
1072 /* Crash on the debugger console */
1073 DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
1074 " (0x%p,0x%p,0x%p,0x%p)\n\n",
1081 /* Check if the debugger isn't currently connected */
1082 if (!KdDebuggerNotPresent
)
1084 /* Check if we have a driver to blame */
1085 if (KiBugCheckDriver
)
1088 DbgPrint("Driver at fault: %s.\n", AnsiName
);
1091 /* Check if this was a hard error */
1094 /* Print caption and message */
1095 if (HardErrCaption
) DbgPrint(HardErrCaption
);
1096 if (HardErrMessage
) DbgPrint(HardErrMessage
);
1099 /* Break in the debugger */
1100 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST
);
1106 * Ok, so debugging is enabled, but KDBG isn't there.
1107 * We'll manually dump the stack for the user.
1109 KeRosDumpStackFrames(NULL
, 0);
1111 /* ROS HACK 2: Generate something useful for Bugzilla */
1112 KeRosDumpTriageForBugZillaReport();
1116 /* Raise IRQL to HIGH_LEVEL */
1118 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1120 /* Avoid recursion */
1121 if (!InterlockedDecrement((PLONG
)&KeBugCheckCount
))
1124 /* Set CPU that is bug checking now */
1125 KeBugCheckOwner
= Prcb
->Number
;
1127 /* Freeze the other CPUs */
1128 for (i
= 0; i
< KeNumberProcessors
; i
++)
1130 if (i
!= (LONG
)KeGetCurrentProcessorNumber())
1132 /* Send the IPI and give them one second to catch up */
1133 KiIpiSend(1 << i
, IPI_FREEZE
);
1134 KeStallExecutionProcessor(1000000);
1139 /* Display the BSOD */
1140 KiDisplayBlueScreen(MessageId
,
1146 /* Check if the debugger is disabled but we can enable it */
1147 if (!(KdDebuggerEnabled
) && !(KdPitchDebugger
))
1151 KdEnableDebuggerWithLock(FALSE
);
1156 /* Otherwise, print the last line */
1157 InbvDisplayString("\r\n");
1160 /* Save the context */
1161 Prcb
->ProcessorState
.ContextFrame
= Context
;
1163 /* FIXME: Support Triage Dump */
1165 /* FIXME: Write the crash dump */
1169 /* Increase recursion count */
1170 KeBugCheckOwnerRecursionCount
++;
1171 if (KeBugCheckOwnerRecursionCount
== 2)
1173 /* Break in the debugger */
1174 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND
);
1176 else if (KeBugCheckOwnerRecursionCount
> 2)
1178 /* Halt execution */
1183 /* Call the Callbacks */
1184 KiDoBugCheckCallbacks();
1186 /* FIXME: Call Watchdog if enabled */
1188 /* Check if we have to reboot */
1191 /* Unload symbols */
1192 DbgUnLoadImageSymbols(NULL
, (PVOID
)MAXULONG_PTR
, 0);
1193 HalReturnToFirmware(HalRebootRoutine
);
1196 /* Attempt to break in the debugger (otherwise halt CPU) */
1197 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND
);
1199 /* Shouldn't get here */
1208 BOOLEAN Handled
= FALSE
;
1209 PKNMI_HANDLER_CALLBACK NmiData
;
1211 /* Parse the list of callbacks */
1212 NmiData
= KiNmiCallbackListHead
;
1215 /* Save if this callback has handled it -- all it takes is one */
1216 Handled
|= NmiData
->Callback(NmiData
->Context
, Handled
);
1217 NmiData
= NmiData
->Next
;
1220 /* Has anyone handled this? */
1224 /* PUBLIC FUNCTIONS **********************************************************/
1231 KeInitializeCrashDumpHeader(IN ULONG Type
,
1234 IN ULONG BufferSize
,
1235 OUT ULONG BufferNeeded OPTIONAL
)
1238 return STATUS_UNSUCCESSFUL
;
1246 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
)
1249 BOOLEAN Status
= FALSE
;
1251 /* Raise IRQL to High */
1252 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1254 /* Check the Current State */
1255 if (CallbackRecord
->State
== BufferInserted
)
1257 /* Reset state and remove from list */
1258 CallbackRecord
->State
= BufferEmpty
;
1259 RemoveEntryList(&CallbackRecord
->Entry
);
1263 /* Lower IRQL and return */
1264 KeLowerIrql(OldIrql
);
1273 KeDeregisterBugCheckReasonCallback(
1274 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
)
1277 BOOLEAN Status
= FALSE
;
1279 /* Raise IRQL to High */
1280 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1282 /* Check the Current State */
1283 if (CallbackRecord
->State
== BufferInserted
)
1285 /* Reset state and remove from list */
1286 CallbackRecord
->State
= BufferEmpty
;
1287 RemoveEntryList(&CallbackRecord
->Entry
);
1291 /* Lower IRQL and return */
1292 KeLowerIrql(OldIrql
);
1301 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
,
1302 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine
,
1305 IN PUCHAR Component
)
1308 BOOLEAN Status
= FALSE
;
1310 /* Raise IRQL to High */
1311 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1313 /* Check the Current State first so we don't double-register */
1314 if (CallbackRecord
->State
== BufferEmpty
)
1316 /* Set the Callback Settings and insert into the list */
1317 CallbackRecord
->Length
= Length
;
1318 CallbackRecord
->Buffer
= Buffer
;
1319 CallbackRecord
->Component
= Component
;
1320 CallbackRecord
->CallbackRoutine
= CallbackRoutine
;
1321 CallbackRecord
->State
= BufferInserted
;
1322 InsertTailList(&KeBugcheckCallbackListHead
, &CallbackRecord
->Entry
);
1326 /* Lower IRQL and return */
1327 KeLowerIrql(OldIrql
);
1336 KeRegisterBugCheckReasonCallback(
1337 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
,
1338 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine
,
1339 IN KBUGCHECK_CALLBACK_REASON Reason
,
1340 IN PUCHAR Component
)
1343 BOOLEAN Status
= FALSE
;
1345 /* Raise IRQL to High */
1346 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1348 /* Check the Current State first so we don't double-register */
1349 if (CallbackRecord
->State
== BufferEmpty
)
1351 /* Set the Callback Settings and insert into the list */
1352 CallbackRecord
->Component
= Component
;
1353 CallbackRecord
->CallbackRoutine
= CallbackRoutine
;
1354 CallbackRecord
->State
= BufferInserted
;
1355 CallbackRecord
->Reason
= Reason
;
1356 InsertTailList(&KeBugcheckReasonCallbackListHead
,
1357 &CallbackRecord
->Entry
);
1361 /* Lower IRQL and return */
1362 KeLowerIrql(OldIrql
);
1371 KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine
,
1375 PKNMI_HANDLER_CALLBACK NmiData
, Next
;
1376 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1378 /* Allocate NMI callback data */
1379 NmiData
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*NmiData
), TAG_KNMI
);
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(IN PVOID Handle
)
1408 PKNMI_HANDLER_CALLBACK NmiData
;
1409 PKNMI_HANDLER_CALLBACK
* Previous
;
1410 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL
);
1412 /* Find in the list the NMI callback corresponding to the handle */
1413 KiAcquireNmiListLock(&OldIrql
);
1414 Previous
= &KiNmiCallbackListHead
;
1415 NmiData
= *Previous
;
1418 if (NmiData
->Handle
== Handle
)
1420 /* The handle is the pointer to the callback itself */
1421 ASSERT(Handle
== NmiData
);
1423 /* Found it, remove from the list */
1424 *Previous
= NmiData
->Next
;
1428 /* Not found; try again */
1429 Previous
= &NmiData
->Next
;
1430 NmiData
= *Previous
;
1432 KiReleaseNmiListLock(OldIrql
);
1434 /* If we have found the entry, free it */
1437 ExFreePoolWithTag(NmiData
, TAG_KNMI
);
1438 return STATUS_SUCCESS
;
1441 return STATUS_INVALID_HANDLE
;
1449 KeBugCheckEx(IN ULONG BugCheckCode
,
1450 IN ULONG_PTR BugCheckParameter1
,
1451 IN ULONG_PTR BugCheckParameter2
,
1452 IN ULONG_PTR BugCheckParameter3
,
1453 IN ULONG_PTR BugCheckParameter4
)
1455 /* Call the internal API */
1456 KeBugCheckWithTf(BugCheckCode
,
1469 KeBugCheck(ULONG BugCheckCode
)
1471 /* Call the internal API */
1472 KeBugCheckWithTf(BugCheckCode
, 0, 0, 0, 0, NULL
);
1480 KeEnterKernelDebugger(VOID
)
1482 /* Disable interrupts */
1483 KiHardwareTrigger
= 1;
1486 /* Check the bugcheck count */
1487 if (!InterlockedDecrement((PLONG
)&KeBugCheckCount
))
1489 /* There was only one, is the debugger disabled? */
1490 if (!(KdDebuggerEnabled
) && !(KdPitchDebugger
))
1492 /* Enable the debugger */
1493 KdInitSystem(0, NULL
);
1497 /* Break in the debugger */
1498 KiBugCheckDebugBreak(DBG_STATUS_FATAL
);