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