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 ******************************************************************/
13 #include <internal/debug.h>
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 PRTL_MESSAGE_RESOURCE_DATA KiBugCodeMessages
;
27 ULONG KeBugCheckCount
= 1;
28 ULONG KiHardwareTrigger
;
29 PUNICODE_STRING KiBugCheckDriver
;
30 ULONG_PTR KiBugCheckData
[5];
32 /* PRIVATE FUNCTIONS *********************************************************/
36 KiPcToFileHeader(IN PVOID Eip
,
37 OUT PLDR_DATA_TABLE_ENTRY
*LdrEntry
,
38 IN BOOLEAN DriversOnly
,
39 OUT PBOOLEAN InKernel
)
42 PVOID ImageBase
, EipBase
= NULL
;
43 PLDR_DATA_TABLE_ENTRY Entry
;
44 PLIST_ENTRY ListHead
, NextEntry
;
46 /* Check which list we should use */
47 ListHead
= (KeLoaderBlock
) ? &KeLoaderBlock
->LoadOrderListHead
:
53 /* Set list pointers and make sure it's valid */
54 NextEntry
= ListHead
->Flink
;
58 while (NextEntry
!= ListHead
)
63 /* Check if this is a kernel entry and we only want drivers */
64 if ((i
<= 2) && (DriversOnly
== TRUE
))
67 NextEntry
= NextEntry
->Flink
;
71 /* Get the loader entry */
72 Entry
= CONTAINING_RECORD(NextEntry
,
76 /* Move to the next entry */
77 NextEntry
= NextEntry
->Flink
;
78 ImageBase
= Entry
->DllBase
;
80 /* Check if this is the right one */
81 if (((ULONG_PTR
)Eip
>= (ULONG_PTR
)Entry
->DllBase
) &&
82 ((ULONG_PTR
)Eip
< ((ULONG_PTR
)Entry
->DllBase
+ Entry
->SizeOfImage
)))
84 /* Return this entry */
88 /* Check if this was a kernel or HAL entry */
89 if (i
<= 2) *InKernel
= TRUE
;
95 /* Return the base address */
101 KiRosPrintAddress(PVOID address
)
103 PLIST_ENTRY current_entry
;
104 PLDR_DATA_TABLE_ENTRY current
;
105 extern LIST_ENTRY PsLoadedModuleList
;
106 ULONG_PTR RelativeAddress
;
111 current_entry
= PsLoadedModuleList
.Flink
;
113 while (current_entry
!= &PsLoadedModuleList
)
115 current
= CONTAINING_RECORD(current_entry
,
116 LDR_DATA_TABLE_ENTRY
,
119 if (address
>= (PVOID
)current
->DllBase
&&
120 address
< (PVOID
)((ULONG_PTR
)current
->DllBase
+
121 current
->SizeOfImage
))
123 RelativeAddress
= (ULONG_PTR
)address
-
124 (ULONG_PTR
)current
->DllBase
;
125 DbgPrint("<%wZ: %x>", ¤t
->FullDllName
, RelativeAddress
);
128 current_entry
= current_entry
->Flink
;
137 KeRosDumpStackFrames(IN PULONG Frame OPTIONAL
,
138 IN ULONG FrameCount OPTIONAL
)
143 PLDR_DATA_TABLE_ENTRY LdrEntry
;
145 /* If the caller didn't ask, assume 32 frames */
146 if (!FrameCount
) FrameCount
= 32;
148 /* Get the current frames */
149 FrameCount
= RtlCaptureStackBackTrace(2, FrameCount
, (PVOID
*)Frames
, NULL
);
151 /* Now loop them (skip the two. One for the dumper, one for the caller) */
152 for (i
= 0; i
< FrameCount
; i
++)
157 /* If we had a custom frame, make sure we've reached it first */
158 if ((Frame
) && (Frame
[1] == Addr
))
164 /* Skip this entry */
168 /* Get the base for this file */
169 if (KiPcToFileHeader((PVOID
)Addr
, &LdrEntry
, FALSE
, &InSystem
))
171 /* Print out the module name */
172 Addr
-= (ULONG_PTR
)LdrEntry
->DllBase
;
173 DbgPrint("<%wZ: %x>", &LdrEntry
->FullDllName
, Addr
);
176 /* Go to the next frame */
180 /* Finish the output */
187 KiInitializeBugCheck(VOID
)
189 PRTL_MESSAGE_RESOURCE_DATA BugCheckData
;
190 LDR_RESOURCE_INFO ResourceInfo
;
191 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry
;
193 PLDR_DATA_TABLE_ENTRY LdrEntry
;
195 /* Get the kernel entry */
196 LdrEntry
= CONTAINING_RECORD(KeLoaderBlock
->LoadOrderListHead
.Flink
,
197 LDR_DATA_TABLE_ENTRY
,
200 /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
201 ResourceInfo
.Type
= 11;
202 ResourceInfo
.Name
= 1;
203 ResourceInfo
.Language
= 9;
206 Status
= LdrFindResource_U(LdrEntry
->DllBase
,
211 /* Make sure it worked */
212 if (NT_SUCCESS(Status
))
214 /* Now actually get a pointer to it */
215 Status
= LdrAccessResource(LdrEntry
->DllBase
,
217 (PVOID
*)&BugCheckData
,
219 if (NT_SUCCESS(Status
)) KiBugCodeMessages
= BugCheckData
;
225 KeGetBugMessageText(IN ULONG BugCheckCode
,
226 OUT PANSI_STRING OutputString OPTIONAL
)
230 ULONG_PTR MessageEntry
;
232 BOOLEAN Result
= FALSE
;
234 /* Make sure we're not bugchecking too early */
235 if (!KiBugCodeMessages
) return Result
;
237 /* Find the message. This code is based on RtlFindMesssage */
238 for (i
= 0; i
< KiBugCodeMessages
->NumberOfBlocks
; i
++)
240 /* Check if the ID Matches */
241 if ((BugCheckCode
>= KiBugCodeMessages
->Blocks
[i
].LowId
) &&
242 (BugCheckCode
<= KiBugCodeMessages
->Blocks
[i
].HighId
))
244 /* Get Offset to Entry */
245 MessageEntry
= KiBugCodeMessages
->Blocks
[i
].OffsetToEntries
+
246 (ULONG_PTR
)KiBugCodeMessages
;
247 IdOffset
= BugCheckCode
- KiBugCodeMessages
->Blocks
[i
].LowId
;
249 /* Get offset to ID */
250 for (i
= 0; i
< IdOffset
; i
++)
252 /* Advance in the Entries */
253 MessageEntry
+= ((PRTL_MESSAGE_RESOURCE_ENTRY
)MessageEntry
)->
257 /* Get the final Code */
258 BugCode
= ((PRTL_MESSAGE_RESOURCE_ENTRY
)MessageEntry
)->Text
;
261 /* Handle newlines */
262 while ((i
> 0) && ((BugCode
[i
] == '\n') ||
263 (BugCode
[i
] == '\r') ||
264 (BugCode
[i
] == ANSI_NULL
)))
266 /* Check if we have a string to return */
267 if (!OutputString
) BugCode
[i
] = ANSI_NULL
;
271 /* Check if caller wants an output string */
274 /* Return it in the OutputString */
275 OutputString
->Buffer
= BugCode
;
276 OutputString
->Length
= (USHORT
)i
+ 1;
277 OutputString
->MaximumLength
= (USHORT
)i
+ 1;
281 /* Direct Output to Screen */
282 InbvDisplayString(BugCode
);
283 InbvDisplayString("\r");
292 /* Return the result */
298 KiDoBugCheckCallbacks(VOID
)
300 PKBUGCHECK_CALLBACK_RECORD CurrentRecord
;
301 PLIST_ENTRY ListHead
, NextEntry
, LastEntry
;
304 /* First make sure that the list is Initialized... it might not be */
305 ListHead
= &KeBugcheckCallbackListHead
;
306 if ((ListHead
->Flink
) && (ListHead
->Blink
))
309 LastEntry
= ListHead
;
310 NextEntry
= ListHead
->Flink
;
311 while (NextEntry
!= ListHead
)
314 CurrentRecord
= CONTAINING_RECORD(NextEntry
,
315 KBUGCHECK_CALLBACK_RECORD
,
319 if (CurrentRecord
->Entry
.Blink
!= LastEntry
) return;
320 Checksum
= (ULONG_PTR
)CurrentRecord
->CallbackRoutine
;
321 Checksum
+= (ULONG_PTR
)CurrentRecord
->Buffer
;
322 Checksum
+= (ULONG_PTR
)CurrentRecord
->Length
;
323 Checksum
+= (ULONG_PTR
)CurrentRecord
->Component
;
325 /* Make sure it's inserted and valitdated */
326 if ((CurrentRecord
->State
== BufferInserted
) &&
327 (CurrentRecord
->Checksum
== Checksum
))
329 /* Call the routine */
330 CurrentRecord
->State
= BufferStarted
;
331 (CurrentRecord
->CallbackRoutine
)(CurrentRecord
->Buffer
,
332 CurrentRecord
->Length
);
333 CurrentRecord
->State
= BufferFinished
;
336 /* Go to the next entry */
337 LastEntry
= NextEntry
;
338 NextEntry
= NextEntry
->Flink
;
345 KiBugCheckDebugBreak(IN ULONG StatusCode
)
347 /* If KDBG isn't connected, freeze the CPU, otherwise, break */
348 if (KdDebuggerNotPresent
) for (;;) Ke386HaltProcessor();
349 DbgBreakPointWithStatus(StatusCode
);
354 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode
,
362 /* Set length and normalize it */
363 i
= Unicode
->Length
/ sizeof(WCHAR
);
364 i
= min(i
, Length
- 1);
366 /* Set source and destination, and copy */
367 pw
= Unicode
->Buffer
;
369 while (i
--) *p
++ = (CHAR
)*pw
++;
371 /* Null terminate and return */
378 KiDumpParameterImages(IN PCHAR Message
,
379 IN PULONG_PTR Parameters
,
380 IN ULONG ParameterCount
,
381 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine
)
385 PLDR_DATA_TABLE_ENTRY LdrEntry
;
387 PUNICODE_STRING DriverName
;
389 PIMAGE_NT_HEADERS NtHeader
;
391 BOOLEAN FirstRun
= TRUE
;
393 /* Loop parameters */
394 for (i
= 0; i
< ParameterCount
; i
++)
396 /* Get the base for this parameter */
397 ImageBase
= KiPcToFileHeader((PVOID
)Parameters
[i
],
403 /* Driver wasn't found, check for unloaded driver */
404 DriverName
= NULL
; // FIXME: ROS can't
405 if (!DriverName
) continue;
407 /* Convert the driver name */
408 ImageBase
= (PVOID
)Parameters
[i
];
409 ConversionRoutine(DriverName
, AnsiName
, sizeof(AnsiName
));
413 /* Get the NT Headers and Timestamp */
414 NtHeader
= RtlImageNtHeader(LdrEntry
->DllBase
);
415 TimeStamp
= NtHeader
->FileHeader
.TimeDateStamp
;
417 /* Convert the driver name */
418 DriverName
= &LdrEntry
->BaseDllName
;
419 ConversionRoutine(&LdrEntry
->BaseDllName
,
424 /* Format driver name */
426 "%s** %12s - Address %p base at %p, DateStamp %08lx\n",
427 FirstRun
? "\r\n*":"*",
429 (PVOID
)Parameters
[i
],
433 /* Check if we only had one parameter */
434 if (ParameterCount
<= 1)
436 /* Then just save the name */
437 KiBugCheckDriver
= DriverName
;
441 /* Otherwise, display the message */
442 InbvDisplayString(Message
);
452 KiDisplayBlueScreen(IN ULONG MessageId
,
453 IN BOOLEAN IsHardError
,
454 IN PCHAR HardErrCaption OPTIONAL
,
455 IN PCHAR HardErrMessage OPTIONAL
,
460 /* Check if bootvid is installed */
461 if (InbvIsBootDriverInstalled())
463 /* Acquire ownership and reset the display */
464 InbvAcquireDisplayOwnership();
467 /* Display blue screen */
468 InbvSolidColorFill(0, 0, 1200-1, 900-1, 4);
469 InbvSetTextColor(15);
470 InbvInstallDisplayStringFilter(NULL
);
471 InbvEnableDisplayString(TRUE
);
472 InbvSetScrollRegion(0, 0, 1200-1, 900-1);
475 /* Check if this is a hard error */
478 /* Display caption and message */
479 if (HardErrCaption
) InbvDisplayString(HardErrCaption
);
480 if (HardErrMessage
) InbvDisplayString(HardErrMessage
);
483 /* Begin the display */
484 InbvDisplayString("\r\n");
486 /* Print out initial message */
487 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO
, NULL
);
488 InbvDisplayString("\r\n\r\n");
490 /* Check if we have a driver */
491 if (KiBugCheckDriver
)
493 /* Print out into to driver name */
494 KeGetBugMessageText(BUGCODE_ID_DRIVER
, NULL
);
496 /* Convert and print out driver name */
497 KeBugCheckUnicodeToAnsi(KiBugCheckDriver
, AnsiName
, sizeof(AnsiName
));
498 InbvDisplayString(" ");
499 InbvDisplayString(AnsiName
);
500 InbvDisplayString("\r\n\r\n");
503 /* Check if this is the generic message */
504 if (MessageId
== BUGCODE_PSS_MESSAGE
)
506 /* It is, so get the bug code string as well */
507 KeGetBugMessageText(KiBugCheckData
[0], NULL
);
508 InbvDisplayString("\r\n\r\n");
511 /* Print second introduction message */
512 KeGetBugMessageText(PSS_MESSAGE_INTRO
, NULL
);
513 InbvDisplayString("\r\n\r\n");
515 /* Get the bug code string */
516 KeGetBugMessageText(MessageId
, NULL
);
517 InbvDisplayString("\r\n\r\n");
519 /* Print message for technical information */
520 KeGetBugMessageText(BUGCHECK_TECH_INFO
, NULL
);
522 /* Show the technical Data */
524 "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
526 (PVOID
)KiBugCheckData
[1],
527 (PVOID
)KiBugCheckData
[2],
528 (PVOID
)KiBugCheckData
[3],
529 (PVOID
)KiBugCheckData
[4]);
530 InbvDisplayString(AnsiName
);
532 /* Check if we have a driver*/
533 if (KiBugCheckDriver
)
535 /* Display technical driver data */
536 InbvDisplayString(Message
);
540 /* Dump parameter information */
541 KiDumpParameterImages(Message
,
542 (PVOID
)&KiBugCheckData
[1],
544 KeBugCheckUnicodeToAnsi
);
550 KeBugCheckWithTf(IN ULONG BugCheckCode
,
551 IN ULONG_PTR BugCheckParameter1
,
552 IN ULONG_PTR BugCheckParameter2
,
553 IN ULONG_PTR BugCheckParameter3
,
554 IN ULONG_PTR BugCheckParameter4
,
555 IN PKTRAP_FRAME TrapFrame
)
557 PKPRCB Prcb
= KeGetCurrentPrcb();
561 BOOLEAN IsSystem
, IsHardError
= FALSE
, Reboot
= FALSE
;
562 PCHAR HardErrCaption
= NULL
, HardErrMessage
= NULL
;
563 PVOID Eip
= NULL
, Memory
;
565 PLDR_DATA_TABLE_ENTRY LdrEntry
;
566 PULONG_PTR HardErrorParameters
;
572 /* Set active bugcheck */
573 KeBugCheckActive
= TRUE
;
574 KiBugCheckDriver
= NULL
;
576 /* Check if this is power failure simulation */
577 if (BugCheckCode
== POWER_FAILURE_SIMULATE
)
579 /* Call the Callbacks and reboot */;
580 KiDoBugCheckCallbacks();
581 HalReturnToFirmware(HalRebootRoutine
);
584 /* Save the IRQL and set hardware trigger */
585 Prcb
->DebuggerSavedIRQL
= KeGetCurrentIrql();
586 InterlockedIncrement((PLONG
)&KiHardwareTrigger
);
588 /* Capture the CPU Context */
589 RtlCaptureContext(&Prcb
->ProcessorState
.ContextFrame
);
590 KiSaveProcessorControlState(&Prcb
->ProcessorState
);
591 Context
= Prcb
->ProcessorState
.ContextFrame
;
593 /* FIXME: Call the Watchdog if it's registered */
595 /* Check which bugcode this is */
596 switch (BugCheckCode
)
598 /* These bug checks already have detailed messages, keep them */
599 case UNEXPECTED_KERNEL_MODE_TRAP
:
600 case DRIVER_CORRUPTED_EXPOOL
:
601 case ACPI_BIOS_ERROR
:
602 case ACPI_BIOS_FATAL_ERROR
:
603 case THREAD_STUCK_IN_DEVICE_DRIVER
:
605 case FAT_FILE_SYSTEM
:
606 case NO_MORE_SYSTEM_PTES
:
607 case INACCESSIBLE_BOOT_DEVICE
:
609 /* Keep the same code */
610 MessageId
= BugCheckCode
;
613 /* Check if this is a kernel-mode exception */
614 case KERNEL_MODE_EXCEPTION_NOT_HANDLED
:
615 //case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED:
616 case KMODE_EXCEPTION_NOT_HANDLED
:
618 /* Use the generic text message */
619 MessageId
= KMODE_EXCEPTION_NOT_HANDLED
;
622 /* File-system errors */
623 case NTFS_FILE_SYSTEM
:
625 /* Use the generic message for FAT */
626 MessageId
= FAT_FILE_SYSTEM
;
629 /* Check if this is a coruption of the Mm's Pool */
630 case DRIVER_CORRUPTED_MMPOOL
:
632 /* Use generic corruption message */
633 MessageId
= DRIVER_CORRUPTED_EXPOOL
;
636 /* Check if this is a signature check failure */
637 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
:
639 /* Use the generic corruption message */
640 MessageId
= BUGCODE_PSS_MESSAGE_SIGNATURE
;
643 /* All other codes */
646 /* Use the default bugcheck message */
647 MessageId
= BUGCODE_PSS_MESSAGE
;
651 /* Save bugcheck data */
652 KiBugCheckData
[0] = BugCheckCode
;
653 KiBugCheckData
[1] = BugCheckParameter1
;
654 KiBugCheckData
[2] = BugCheckParameter2
;
655 KiBugCheckData
[3] = BugCheckParameter3
;
656 KiBugCheckData
[4] = BugCheckParameter4
;
658 /* Now check what bugcheck this is */
659 switch (BugCheckCode
)
661 /* Invalid access to R/O memory or Unhandled KM Exception */
662 case KERNEL_MODE_EXCEPTION_NOT_HANDLED
:
663 case ATTEMPTED_WRITE_TO_READONLY_MEMORY
:
664 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY
:
666 /* Check if we have a trap frame */
669 /* Use parameter 3 as a trap frame, if it exists */
670 if (BugCheckParameter3
) TrapFrame
= (PVOID
)BugCheckParameter3
;
673 /* Check if we got one now and if we need to get EIP */
675 (BugCheckCode
!= KERNEL_MODE_EXCEPTION_NOT_HANDLED
))
678 Eip
= (PVOID
)TrapFrame
->Eip
;
683 case IRQL_NOT_LESS_OR_EQUAL
:
686 * The NT kernel has 3 special sections:
687 * MISYSPTE, POOLMI and POOLCODE. The bug check code can
688 * determine in which of these sections this bugcode happened
689 * and provide a more detailed analysis. For now, we don't.
692 /* Eip is in parameter 4 */
693 Eip
= (PVOID
)BugCheckParameter4
;
695 /* Get the driver base */
696 DriverBase
= KiPcToFileHeader(Eip
, &LdrEntry
, FALSE
, &IsSystem
);
700 * The error happened inside the kernel or HAL.
701 * Get the memory address that was being referenced.
703 Memory
= (PVOID
)BugCheckParameter1
;
705 /* Find to which driver it belongs */
706 DriverBase
= KiPcToFileHeader(Memory
,
712 /* Get the driver name and update the bug code */
713 KiBugCheckDriver
= &LdrEntry
->BaseDllName
;
714 KiBugCheckData
[0] = DRIVER_PORTION_MUST_BE_NONPAGED
;
718 /* Find the driver that unloaded at this address */
719 KiBugCheckDriver
= NULL
; // FIXME: ROS can't locate
721 /* Check if the cause was an unloaded driver */
722 if (KiBugCheckDriver
)
724 /* Update bug check code */
726 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD
;
732 /* Update the bug check code */
733 KiBugCheckData
[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL
;
736 /* Clear EIP so we don't look it up later */
741 case FATAL_UNHANDLED_HARD_ERROR
:
743 /* Copy bug check data from hard error */
744 HardErrorParameters
= (PULONG_PTR
)BugCheckParameter2
;
745 KiBugCheckData
[0] = BugCheckParameter1
;
746 KiBugCheckData
[1] = HardErrorParameters
[0];
747 KiBugCheckData
[2] = HardErrorParameters
[1];
748 KiBugCheckData
[3] = HardErrorParameters
[2];
749 KiBugCheckData
[4] = HardErrorParameters
[3];
751 /* Remember that this is hard error and set the caption/message */
753 HardErrCaption
= (PCHAR
)BugCheckParameter3
;
754 HardErrMessage
= (PCHAR
)BugCheckParameter4
;
758 case PAGE_FAULT_IN_NONPAGED_AREA
:
760 /* Assume no driver */
763 /* Check if we have a trap frame */
766 /* We don't, use parameter 3 if possible */
767 if (BugCheckParameter3
) TrapFrame
= (PVOID
)BugCheckParameter3
;
770 /* Check if we have a frame now */
774 Eip
= (PVOID
)TrapFrame
->Eip
;
775 KiBugCheckData
[3] = (ULONG
)Eip
;
777 /* Find out if was in the kernel or drivers */
778 DriverBase
= KiPcToFileHeader(Eip
,
785 * Now we should check if this happened in:
786 * 1) Special Pool 2) Free Special Pool 3) Session Pool
787 * and update the bugcheck code appropriately.
790 /* Check if we didn't have a driver base */
793 /* Find the driver that unloaded at this address */
794 KiBugCheckDriver
= NULL
; // FIXME: ROS can't locate
796 /* Check if the cause was an unloaded driver */
797 if (KiBugCheckDriver
)
800 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS
;
805 /* Check if the driver forgot to unlock pages */
806 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS
:
808 /* EIP is in parameter 1 */
809 Eip
= (PVOID
)BugCheckParameter1
;
812 /* Check if the driver consumed too many PTEs */
813 case DRIVER_USED_EXCESSIVE_PTES
:
815 /* Loader entry is in parameter 1 */
816 LdrEntry
= (PVOID
)BugCheckParameter1
;
817 KiBugCheckDriver
= &LdrEntry
->BaseDllName
;
820 /* Check if the driver has a stuck thread */
821 case THREAD_STUCK_IN_DEVICE_DRIVER
:
823 /* The name is in Parameter 3 */
824 KiBugCheckDriver
= (PVOID
)BugCheckParameter3
;
832 /* Do we have a driver name? */
833 if (KiBugCheckDriver
)
835 /* Convert it to ANSI */
836 KeBugCheckUnicodeToAnsi(KiBugCheckDriver
, AnsiName
, sizeof(AnsiName
));
840 /* Do we have an EIP? */
843 /* Dump image name */
844 KiDumpParameterImages(AnsiName
,
847 KeBugCheckUnicodeToAnsi
);
851 /* Check if we need to save the context for KD */
853 if (!KdPitchDebugger
) KdDebuggerDataBlock
.SavedContext
= (ULONG
)&Context
;
856 /* Check if a debugger is connected */
857 if ((BugCheckCode
!= MANUALLY_INITIATED_CRASH
) && (KdDebuggerEnabled
))
859 /* Crash on the debugger console */
860 DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
861 " (0x%p,0x%p,0x%p,0x%p)\n\n",
868 /* Check if the debugger isn't currently connected */
869 if (!KdDebuggerNotPresent
)
871 /* Check if we have a driver to blame */
872 if (KiBugCheckDriver
)
875 DbgPrint("Driver at fault: %s.\n", AnsiName
);
878 /* Check if this was a hard error */
881 /* Print caption and message */
882 if (HardErrCaption
) DbgPrint(HardErrCaption
);
883 if (HardErrMessage
) DbgPrint(HardErrMessage
);
886 /* Break in the debugger */
887 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST
);
893 * Ok, so debugging is enabled, but KDBG isn't there.
894 * We'll manually dump the stack for the user.
896 KeRosDumpStackFrames(NULL
, 0);
900 /* Raise IRQL to HIGH_LEVEL */
902 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
904 /* ROS HACK: Unlock the Kernel Address Space if we own it */
905 if (KernelAddressSpaceLock
.Owner
== KeGetCurrentThread())
907 MmUnlockAddressSpace(MmGetKernelAddressSpace());
910 /* Avoid recursion */
911 if (!InterlockedDecrement((PLONG
)&KeBugCheckCount
))
914 /* Set CPU that is bug checking now */
915 KeBugCheckOwner
= Prcb
->Number
;
917 /* Freeze the other CPUs */
918 for (i
= 0; i
< KeNumberProcessors
; i
++)
920 if (i
!= (LONG
)KeGetCurrentProcessorNumber())
922 /* Send the IPI and give them one second to catch up */
923 KiIpiSendRequest(1 << i
, IPI_FREEZE
);
924 KeStallExecutionProcessor(1000000);
929 /* Display the BSOD */
930 KiDisplayBlueScreen(MessageId
,
936 /* Check if the debugger is disabled but we can enable it */
937 if (!(KdDebuggerEnabled
) && !(KdPitchDebugger
))
941 KdEnableDebuggerWithLock(FALSE
);
946 /* Otherwise, print the last line */
947 InbvDisplayString("\r\n");
950 /* Save the context */
951 Prcb
->ProcessorState
.ContextFrame
= Context
;
953 /* FIXME: Support Triage Dump */
955 /* Write the crash dump */
956 MmDumpToPagingFile(KiBugCheckData
[4],
965 /* Increase recursion count */
966 KeBugCheckOwnerRecursionCount
++;
967 if (KeBugCheckOwnerRecursionCount
== 2)
969 /* Break in the debugger */
970 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND
);
972 else if (KeBugCheckOwnerRecursionCount
> 2)
975 for (;;) Ke386HaltProcessor();
979 /* Call the Callbacks */
980 KiDoBugCheckCallbacks();
982 /* FIXME: Call Watchdog if enabled */
984 /* Check if we have to reboot */
988 DbgUnLoadImageSymbols(NULL
, NtCurrentProcess(), 0);
989 HalReturnToFirmware(HalRebootRoutine
);
992 /* Attempt to break in the debugger (otherwise halt CPU) */
993 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND
);
996 /* PUBLIC FUNCTIONS **********************************************************/
1003 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
)
1006 BOOLEAN Status
= FALSE
;
1008 /* Raise IRQL to High */
1009 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1011 /* Check the Current State */
1012 if (CallbackRecord
->State
== BufferInserted
)
1014 /* Reset state and remove from list */
1015 CallbackRecord
->State
= BufferEmpty
;
1016 RemoveEntryList(&CallbackRecord
->Entry
);
1020 /* Lower IRQL and return */
1021 KeLowerIrql(OldIrql
);
1030 KeDeregisterBugCheckReasonCallback(
1031 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
)
1034 BOOLEAN Status
= FALSE
;
1036 /* Raise IRQL to High */
1037 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1039 /* Check the Current State */
1040 if (CallbackRecord
->State
== BufferInserted
)
1042 /* Reset state and remove from list */
1043 CallbackRecord
->State
= BufferEmpty
;
1044 RemoveEntryList(&CallbackRecord
->Entry
);
1048 /* Lower IRQL and return */
1049 KeLowerIrql(OldIrql
);
1058 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord
,
1059 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine
,
1062 IN PUCHAR Component
)
1065 BOOLEAN Status
= FALSE
;
1067 /* Raise IRQL to High */
1068 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1070 /* Check the Current State first so we don't double-register */
1071 if (CallbackRecord
->State
== BufferEmpty
)
1073 /* Set the Callback Settings and insert into the list */
1074 CallbackRecord
->Length
= Length
;
1075 CallbackRecord
->Buffer
= Buffer
;
1076 CallbackRecord
->Component
= Component
;
1077 CallbackRecord
->CallbackRoutine
= CallbackRoutine
;
1078 CallbackRecord
->State
= BufferInserted
;
1079 InsertTailList(&KeBugcheckCallbackListHead
, &CallbackRecord
->Entry
);
1083 /* Lower IRQL and return */
1084 KeLowerIrql(OldIrql
);
1093 KeRegisterBugCheckReasonCallback(
1094 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord
,
1095 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine
,
1096 IN KBUGCHECK_CALLBACK_REASON Reason
,
1097 IN PUCHAR Component
)
1100 BOOLEAN Status
= FALSE
;
1102 /* Raise IRQL to High */
1103 KeRaiseIrql(HIGH_LEVEL
, &OldIrql
);
1105 /* Check the Current State first so we don't double-register */
1106 if (CallbackRecord
->State
== BufferEmpty
)
1108 /* Set the Callback Settings and insert into the list */
1109 CallbackRecord
->Component
= Component
;
1110 CallbackRecord
->CallbackRoutine
= CallbackRoutine
;
1111 CallbackRecord
->State
= BufferInserted
;
1112 CallbackRecord
->Reason
= Reason
;
1113 InsertTailList(&KeBugcheckReasonCallbackListHead
,
1114 &CallbackRecord
->Entry
);
1118 /* Lower IRQL and return */
1119 KeLowerIrql(OldIrql
);
1128 KeBugCheckEx(IN ULONG BugCheckCode
,
1129 IN ULONG_PTR BugCheckParameter1
,
1130 IN ULONG_PTR BugCheckParameter2
,
1131 IN ULONG_PTR BugCheckParameter3
,
1132 IN ULONG_PTR BugCheckParameter4
)
1134 /* Call the internal API */
1135 KeBugCheckWithTf(BugCheckCode
,
1148 KeBugCheck(ULONG BugCheckCode
)
1150 /* Call the internal API */
1151 KeBugCheckWithTf(BugCheckCode
, 0, 0, 0, 0, NULL
);
1159 KeEnterKernelDebugger(VOID
)
1161 /* Disable interrupts */
1162 KiHardwareTrigger
= 1;
1165 /* Check the bugcheck count */
1166 if (!InterlockedDecrement((PLONG
)&KeBugCheckCount
))
1168 /* There was only one, is the debugger disabled? */
1169 if (!(KdDebuggerEnabled
) && !(KdPitchDebugger
))
1171 /* Enable the debugger */
1172 KdInitSystem(0, NULL
);
1177 KiBugCheckDebugBreak(DBG_STATUS_FATAL
);