xref: /reactos/ntoskrnl/ke/bug.c (revision e7354f24)
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 
22 LIST_ENTRY KeBugcheckCallbackListHead;
23 LIST_ENTRY KeBugcheckReasonCallbackListHead;
24 KSPIN_LOCK BugCheckCallbackLock;
25 ULONG KeBugCheckActive, KeBugCheckOwner;
26 LONG KeBugCheckOwnerRecursionCount;
27 PMESSAGE_RESOURCE_DATA KiBugCodeMessages;
28 ULONG KeBugCheckCount = 1;
29 ULONG KiHardwareTrigger;
30 PUNICODE_STRING KiBugCheckDriver;
31 ULONG_PTR KiBugCheckData[5];
32 
33 PKNMI_HANDLER_CALLBACK KiNmiCallbackListHead = NULL;
34 KSPIN_LOCK KiNmiCallbackListLock;
35 
36 /* Jira Reporting */
37 UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion;
38 UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion;
39 
40 /* PRIVATE FUNCTIONS *********************************************************/
41 
42 PVOID
43 NTAPI
KiPcToFileHeader(IN PVOID Pc,OUT PLDR_DATA_TABLE_ENTRY * LdrEntry,IN BOOLEAN DriversOnly,OUT PBOOLEAN InKernel)44 KiPcToFileHeader(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 
107 PVOID
108 NTAPI
KiRosPcToUserFileHeader(IN PVOID Pc,OUT PLDR_DATA_TABLE_ENTRY * LdrEntry)109 KiRosPcToUserFileHeader(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 
156 USHORT
157 NTAPI
KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip,IN ULONG FramesToCapture,OUT PVOID * BackTrace,OUT PULONG BackTraceHash OPTIONAL)158 KeRosCaptureUserStackBackTrace(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 
199 VOID
200 FASTCALL
KeRosDumpStackFrameArray(IN PULONG_PTR Frames,IN ULONG FrameCount)201 KeRosDumpStackFrameArray(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 
260 VOID
261 NTAPI
KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL,IN ULONG FrameCount OPTIONAL)262 KeRosDumpStackFrames(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 
297 CODE_SEG("INIT")
298 VOID
299 NTAPI
KiInitializeBugCheck(VOID)300 KiInitializeBugCheck(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 = 11;
315     ResourceInfo.Name = 1;
316     ResourceInfo.Language = 9;
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 
336 BOOLEAN
337 NTAPI
KeGetBugMessageText(IN ULONG BugCheckCode,OUT PANSI_STRING OutputString OPTIONAL)338 KeGetBugMessageText(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 
434 VOID
435 NTAPI
KiDoBugCheckCallbacks(VOID)436 KiDoBugCheckCallbacks(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 reord */
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 
491 VOID
492 NTAPI
KiBugCheckDebugBreak(IN ULONG StatusCode)493 KiBugCheckDebugBreak(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      */
499 DoBreak:
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 
516 PCHAR
517 NTAPI
KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode,OUT PCHAR Ansi,IN ULONG Length)518 KeBugCheckUnicodeToAnsi(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 
540 VOID
541 NTAPI
KiDumpParameterImages(IN PCHAR Message,IN PULONG_PTR Parameters,IN ULONG ParameterCount,IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine)542 KiDumpParameterImages(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 
610 VOID
611 NTAPI
KiDisplayBlueScreen(IN ULONG MessageId,IN BOOLEAN IsHardError,IN PCHAR HardErrCaption OPTIONAL,IN PCHAR HardErrMessage OPTIONAL,IN PCHAR Message)612 KiDisplayBlueScreen(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 
721 DECLSPEC_NORETURN
722 VOID
723 NTAPI
KeBugCheckWithTf(IN ULONG BugCheckCode,IN ULONG_PTR BugCheckParameter1,IN ULONG_PTR BugCheckParameter2,IN ULONG_PTR BugCheckParameter3,IN ULONG_PTR BugCheckParameter4,IN PKTRAP_FRAME TrapFrame)724 KeBugCheckWithTf(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 
1167 BOOLEAN
1168 NTAPI
KiHandleNmi(VOID)1169 KiHandleNmi(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  */
1192 NTSTATUS
1193 NTAPI
KeInitializeCrashDumpHeader(IN ULONG Type,IN ULONG Flags,OUT PVOID Buffer,IN ULONG BufferSize,OUT ULONG BufferNeeded OPTIONAL)1194 KeInitializeCrashDumpHeader(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  */
1207 BOOLEAN
1208 NTAPI
KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)1209 KeDeregisterBugCheckCallback(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  */
1234 BOOLEAN
1235 NTAPI
KeDeregisterBugCheckReasonCallback(IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)1236 KeDeregisterBugCheckReasonCallback(
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  */
1262 BOOLEAN
1263 NTAPI
KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,IN PVOID Buffer,IN ULONG Length,IN PUCHAR Component)1264 KeRegisterBugCheckCallback(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  */
1297 BOOLEAN
1298 NTAPI
KeRegisterBugCheckReasonCallback(IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,IN KBUGCHECK_CALLBACK_REASON Reason,IN PUCHAR Component)1299 KeRegisterBugCheckReasonCallback(
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  */
1332 PVOID
1333 NTAPI
KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine,IN PVOID Context)1334 KeRegisterNmiCallback(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  */
1366 NTSTATUS
1367 NTAPI
KeDeregisterNmiCallback(IN PVOID Handle)1368 KeDeregisterNmiCallback(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  */
1410 DECLSPEC_NORETURN
1411 VOID
1412 NTAPI
KeBugCheckEx(IN ULONG BugCheckCode,IN ULONG_PTR BugCheckParameter1,IN ULONG_PTR BugCheckParameter2,IN ULONG_PTR BugCheckParameter3,IN ULONG_PTR BugCheckParameter4)1413 KeBugCheckEx(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  */
1431 DECLSPEC_NORETURN
1432 VOID
1433 NTAPI
KeBugCheck(ULONG BugCheckCode)1434 KeBugCheck(ULONG BugCheckCode)
1435 {
1436     /* Call the internal API */
1437     KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL);
1438 }
1439 
1440 /*
1441  * @implemented
1442  */
1443 VOID
1444 NTAPI
KeEnterKernelDebugger(VOID)1445 KeEnterKernelDebugger(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 */
1467