xref: /reactos/ntoskrnl/ke/bug.c (revision 1d289fec)
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     CHAR AnsiName[107];
619 
620     /* Check if bootvid is installed */
621     if (InbvIsBootDriverInstalled())
622     {
623         /* Acquire ownership and reset the display */
624         InbvAcquireDisplayOwnership();
625         InbvResetDisplay();
626 
627         /* Display blue screen */
628         InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLUE);
629         InbvSetTextColor(BV_COLOR_WHITE);
630         InbvInstallDisplayStringFilter(NULL);
631         InbvEnableDisplayString(TRUE);
632         InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
633     }
634 
635     /* Check if this is a hard error */
636     if (IsHardError)
637     {
638         /* Display caption and message */
639         if (HardErrCaption) InbvDisplayString(HardErrCaption);
640         if (HardErrMessage) InbvDisplayString(HardErrMessage);
641     }
642 
643     /* Begin the display */
644     InbvDisplayString("\r\n");
645 
646     /* Print out initial message */
647     KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL);
648     InbvDisplayString("\r\n\r\n");
649 
650     /* Check if we have a driver */
651     if (KiBugCheckDriver)
652     {
653         /* Print out into to driver name */
654         KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
655 
656         /* Convert and print out driver name */
657         KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
658         InbvDisplayString(" ");
659         InbvDisplayString(AnsiName);
660         InbvDisplayString("\r\n\r\n");
661     }
662 
663     /* Check if this is the generic message */
664     if (MessageId == BUGCODE_PSS_MESSAGE)
665     {
666         /* It is, so get the bug code string as well */
667         KeGetBugMessageText((ULONG)KiBugCheckData[0], NULL);
668         InbvDisplayString("\r\n\r\n");
669     }
670 
671     /* Print second introduction message */
672     KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL);
673     InbvDisplayString("\r\n\r\n");
674 
675     /* Get the bug code string */
676     KeGetBugMessageText(MessageId, NULL);
677     InbvDisplayString("\r\n\r\n");
678 
679     /* Print message for technical information */
680     KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
681 
682     /* Show the technical Data */
683     RtlStringCbPrintfA(AnsiName,
684                        sizeof(AnsiName),
685                        "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
686                        (ULONG)KiBugCheckData[0],
687                        (PVOID)KiBugCheckData[1],
688                        (PVOID)KiBugCheckData[2],
689                        (PVOID)KiBugCheckData[3],
690                        (PVOID)KiBugCheckData[4]);
691     InbvDisplayString(AnsiName);
692 
693     /* Check if we have a driver*/
694     if (KiBugCheckDriver)
695     {
696         /* Display technical driver data */
697         InbvDisplayString(Message);
698     }
699     else
700     {
701         /* Dump parameter information */
702         KiDumpParameterImages(Message,
703                               (PVOID)&KiBugCheckData[1],
704                               4,
705                               KeBugCheckUnicodeToAnsi);
706     }
707 }
708 
709 DECLSPEC_NORETURN
710 VOID
711 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)712 KeBugCheckWithTf(IN ULONG BugCheckCode,
713                  IN ULONG_PTR BugCheckParameter1,
714                  IN ULONG_PTR BugCheckParameter2,
715                  IN ULONG_PTR BugCheckParameter3,
716                  IN ULONG_PTR BugCheckParameter4,
717                  IN PKTRAP_FRAME TrapFrame)
718 {
719     PKPRCB Prcb = KeGetCurrentPrcb();
720     CONTEXT Context;
721     ULONG MessageId;
722     CHAR AnsiName[128];
723     BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE;
724     PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
725     PVOID Pc = NULL, Memory;
726     PVOID DriverBase;
727     PLDR_DATA_TABLE_ENTRY LdrEntry;
728     PULONG_PTR HardErrorParameters;
729     KIRQL OldIrql;
730 
731     /* Set active bugcheck */
732     KeBugCheckActive = TRUE;
733     KiBugCheckDriver = NULL;
734 
735     /* Check if this is power failure simulation */
736     if (BugCheckCode == POWER_FAILURE_SIMULATE)
737     {
738         /* Call the Callbacks and reboot */
739         KiDoBugCheckCallbacks();
740         HalReturnToFirmware(HalRebootRoutine);
741     }
742 
743     /* Save the IRQL and set hardware trigger */
744     Prcb->DebuggerSavedIRQL = KeGetCurrentIrql();
745     InterlockedIncrement((PLONG)&KiHardwareTrigger);
746 
747     /* Capture the CPU Context */
748     RtlCaptureContext(&Prcb->ProcessorState.ContextFrame);
749     KiSaveProcessorControlState(&Prcb->ProcessorState);
750     Context = Prcb->ProcessorState.ContextFrame;
751 
752     /* FIXME: Call the Watchdog if it's registered */
753 
754     /* Check which bugcode this is */
755     switch (BugCheckCode)
756     {
757         /* These bug checks already have detailed messages, keep them */
758         case UNEXPECTED_KERNEL_MODE_TRAP:
759         case DRIVER_CORRUPTED_EXPOOL:
760         case ACPI_BIOS_ERROR:
761         case ACPI_BIOS_FATAL_ERROR:
762         case THREAD_STUCK_IN_DEVICE_DRIVER:
763         case DATA_BUS_ERROR:
764         case FAT_FILE_SYSTEM:
765         case NO_MORE_SYSTEM_PTES:
766         case INACCESSIBLE_BOOT_DEVICE:
767 
768             /* Keep the same code */
769             MessageId = BugCheckCode;
770             break;
771 
772         /* Check if this is a kernel-mode exception */
773         case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
774         case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED:
775         case KMODE_EXCEPTION_NOT_HANDLED:
776 
777             /* Use the generic text message */
778             MessageId = KMODE_EXCEPTION_NOT_HANDLED;
779             break;
780 
781         /* File-system errors */
782         case NTFS_FILE_SYSTEM:
783 
784             /* Use the generic message for FAT */
785             MessageId = FAT_FILE_SYSTEM;
786             break;
787 
788         /* Check if this is a coruption of the Mm's Pool */
789         case DRIVER_CORRUPTED_MMPOOL:
790 
791             /* Use generic corruption message */
792             MessageId = DRIVER_CORRUPTED_EXPOOL;
793             break;
794 
795         /* Check if this is a signature check failure */
796         case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
797 
798             /* Use the generic corruption message */
799             MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE;
800             break;
801 
802         /* All other codes */
803         default:
804 
805             /* Use the default bugcheck message */
806             MessageId = BUGCODE_PSS_MESSAGE;
807             break;
808     }
809 
810     /* Save bugcheck data */
811     KiBugCheckData[0] = BugCheckCode;
812     KiBugCheckData[1] = BugCheckParameter1;
813     KiBugCheckData[2] = BugCheckParameter2;
814     KiBugCheckData[3] = BugCheckParameter3;
815     KiBugCheckData[4] = BugCheckParameter4;
816 
817     /* Now check what bugcheck this is */
818     switch (BugCheckCode)
819     {
820         /* Invalid access to R/O memory or Unhandled KM Exception */
821         case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
822         case ATTEMPTED_WRITE_TO_READONLY_MEMORY:
823         case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY:
824         {
825             /* Check if we have a trap frame */
826             if (!TrapFrame)
827             {
828                 /* Use parameter 3 as a trap frame, if it exists */
829                 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
830             }
831 
832             /* Check if we got one now and if we need to get the Program Counter */
833             if ((TrapFrame) &&
834                 (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
835             {
836                 /* Get the Program Counter */
837                 Pc = (PVOID)KeGetTrapFramePc(TrapFrame);
838             }
839             break;
840         }
841 
842         /* Wrong IRQL */
843         case IRQL_NOT_LESS_OR_EQUAL:
844         {
845             /*
846              * The NT kernel has 3 special sections:
847              * MISYSPTE, POOLMI and POOLCODE. The bug check code can
848              * determine in which of these sections this bugcode happened
849              * and provide a more detailed analysis. For now, we don't.
850              */
851 
852             /* Program Counter is in parameter 4 */
853             Pc = (PVOID)BugCheckParameter4;
854 
855             /* Get the driver base */
856             DriverBase = KiPcToFileHeader(Pc,
857                                           &LdrEntry,
858                                           FALSE,
859                                           &IsSystem);
860             if (IsSystem)
861             {
862                 /*
863                  * The error happened inside the kernel or HAL.
864                  * Get the memory address that was being referenced.
865                  */
866                 Memory = (PVOID)BugCheckParameter1;
867 
868                 /* Find to which driver it belongs */
869                 DriverBase = KiPcToFileHeader(Memory,
870                                               &LdrEntry,
871                                               TRUE,
872                                               &IsSystem);
873                 if (DriverBase)
874                 {
875                     /* Get the driver name and update the bug code */
876                     KiBugCheckDriver = &LdrEntry->BaseDllName;
877                     KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED;
878                 }
879                 else
880                 {
881                     /* Find the driver that unloaded at this address */
882                     KiBugCheckDriver = NULL; // FIXME: ROS can't locate
883 
884                     /* Check if the cause was an unloaded driver */
885                     if (KiBugCheckDriver)
886                     {
887                         /* Update bug check code */
888                         KiBugCheckData[0] =
889                             SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD;
890                     }
891                 }
892             }
893             else
894             {
895                 /* Update the bug check code */
896                 KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
897             }
898 
899             /* Clear Pc so we don't look it up later */
900             Pc = NULL;
901             break;
902         }
903 
904         /* Hard error */
905         case FATAL_UNHANDLED_HARD_ERROR:
906         {
907             /* Copy bug check data from hard error */
908             HardErrorParameters = (PULONG_PTR)BugCheckParameter2;
909             KiBugCheckData[0] = BugCheckParameter1;
910             KiBugCheckData[1] = HardErrorParameters[0];
911             KiBugCheckData[2] = HardErrorParameters[1];
912             KiBugCheckData[3] = HardErrorParameters[2];
913             KiBugCheckData[4] = HardErrorParameters[3];
914 
915             /* Remember that this is hard error and set the caption/message */
916             IsHardError = TRUE;
917             HardErrCaption = (PCHAR)BugCheckParameter3;
918             HardErrMessage = (PCHAR)BugCheckParameter4;
919             break;
920         }
921 
922         /* Page fault */
923         case PAGE_FAULT_IN_NONPAGED_AREA:
924         {
925             /* Assume no driver */
926             DriverBase = NULL;
927 
928             /* Check if we have a trap frame */
929             if (!TrapFrame)
930             {
931                 /* We don't, use parameter 3 if possible */
932                 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
933             }
934 
935             /* Check if we have a frame now */
936             if (TrapFrame)
937             {
938                 /* Get the Program Counter */
939                 Pc = (PVOID)KeGetTrapFramePc(TrapFrame);
940                 KiBugCheckData[3] = (ULONG_PTR)Pc;
941 
942                 /* Find out if was in the kernel or drivers */
943                 DriverBase = KiPcToFileHeader(Pc,
944                                               &LdrEntry,
945                                               FALSE,
946                                               &IsSystem);
947             }
948             else
949             {
950                 /* Can't blame a driver, assume system */
951                 IsSystem = TRUE;
952             }
953 
954             /* FIXME: Check for session pool in addition to special pool */
955 
956             /* Special pool has its own bug check codes */
957             if (MmIsSpecialPoolAddress((PVOID)BugCheckParameter1))
958             {
959                 if (MmIsSpecialPoolAddressFree((PVOID)BugCheckParameter1))
960                 {
961                     KiBugCheckData[0] = IsSystem
962                         ? PAGE_FAULT_IN_FREED_SPECIAL_POOL
963                         : DRIVER_PAGE_FAULT_IN_FREED_SPECIAL_POOL;
964                 }
965                 else
966                 {
967                     KiBugCheckData[0] = IsSystem
968                         ? PAGE_FAULT_BEYOND_END_OF_ALLOCATION
969                         : DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION;
970                 }
971             }
972             else if (!DriverBase)
973             {
974                 /* Find the driver that unloaded at this address */
975                 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
976 
977                 /* Check if the cause was an unloaded driver */
978                 if (KiBugCheckDriver)
979                 {
980                     KiBugCheckData[0] =
981                         DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS;
982                 }
983             }
984             break;
985         }
986 
987         /* Check if the driver forgot to unlock pages */
988         case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
989 
990             /* Program Counter is in parameter 1 */
991             Pc = (PVOID)BugCheckParameter1;
992             break;
993 
994         /* Check if the driver consumed too many PTEs */
995         case DRIVER_USED_EXCESSIVE_PTES:
996 
997             /* Loader entry is in parameter 1 */
998             LdrEntry = (PVOID)BugCheckParameter1;
999             KiBugCheckDriver = &LdrEntry->BaseDllName;
1000             break;
1001 
1002         /* Check if the driver has a stuck thread */
1003         case THREAD_STUCK_IN_DEVICE_DRIVER:
1004 
1005             /* The name is in Parameter 3 */
1006             KiBugCheckDriver = (PVOID)BugCheckParameter3;
1007             break;
1008 
1009         /* Anything else */
1010         default:
1011             break;
1012     }
1013 
1014     /* Do we have a driver name? */
1015     if (KiBugCheckDriver)
1016     {
1017         /* Convert it to ANSI */
1018         KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
1019     }
1020     else
1021     {
1022         /* Do we have a Program Counter? */
1023         if (Pc)
1024         {
1025             /* Dump image name */
1026             KiDumpParameterImages(AnsiName,
1027                                   (PULONG_PTR)&Pc,
1028                                   1,
1029                                   KeBugCheckUnicodeToAnsi);
1030         }
1031     }
1032 
1033     /* Check if we need to save the context for KD */
1034     if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG_PTR)&Context;
1035 
1036     /* Check if a debugger is connected */
1037     if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
1038     {
1039         /* Crash on the debugger console */
1040         DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
1041                  "                       (0x%p,0x%p,0x%p,0x%p)\n\n",
1042                  KiBugCheckData[0],
1043                  KiBugCheckData[1],
1044                  KiBugCheckData[2],
1045                  KiBugCheckData[3],
1046                  KiBugCheckData[4]);
1047 
1048         /* Check if the debugger isn't currently connected */
1049         if (!KdDebuggerNotPresent)
1050         {
1051             /* Check if we have a driver to blame */
1052             if (KiBugCheckDriver)
1053             {
1054                 /* Dump it */
1055                 DbgPrint("Driver at fault: %s.\n", AnsiName);
1056             }
1057 
1058             /* Check if this was a hard error */
1059             if (IsHardError)
1060             {
1061                 /* Print caption and message */
1062                 if (HardErrCaption) DbgPrint(HardErrCaption);
1063                 if (HardErrMessage) DbgPrint(HardErrMessage);
1064             }
1065 
1066             /* Break in the debugger */
1067             KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST);
1068         }
1069     }
1070 
1071     /* Raise IRQL to HIGH_LEVEL */
1072     _disable();
1073     KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1074 
1075     /* Avoid recursion */
1076     if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
1077     {
1078 #ifdef CONFIG_SMP
1079         /* Set CPU that is bug checking now */
1080         KeBugCheckOwner = Prcb->Number;
1081 
1082         /* Freeze the other CPUs */
1083         for (ULONG i = 0; i < KeNumberProcessors; i++)
1084         {
1085             if (i != Prcb->Number)
1086             {
1087                 /* Send the IPI */
1088                 KiIpiSend(AFFINITY_MASK(i), IPI_FREEZE);
1089             }
1090         }
1091 
1092         /* Give the other CPUs one second to catch up */
1093         KeStallExecutionProcessor(1000000);
1094 #endif
1095 
1096         /* Display the BSOD */
1097         KiDisplayBlueScreen(MessageId,
1098                             IsHardError,
1099                             HardErrCaption,
1100                             HardErrMessage,
1101                             AnsiName);
1102 
1103         // TODO/FIXME: Run the registered reason-callbacks from
1104         // the KeBugcheckReasonCallbackListHead list with the
1105         // KbCallbackReserved1 reason.
1106 
1107         /* Check if the debugger is disabled but we can enable it */
1108         if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1109         {
1110             /* Enable it */
1111             KdEnableDebuggerWithLock(FALSE);
1112         }
1113         else
1114         {
1115             /* Otherwise, print the last line */
1116             InbvDisplayString("\r\n");
1117         }
1118 
1119         /* Save the context */
1120         Prcb->ProcessorState.ContextFrame = Context;
1121 
1122         /* FIXME: Support Triage Dump */
1123 
1124         /* FIXME: Write the crash dump */
1125     }
1126     else
1127     {
1128         /* Increase recursion count */
1129         KeBugCheckOwnerRecursionCount++;
1130         if (KeBugCheckOwnerRecursionCount == 2)
1131         {
1132             /* Break in the debugger */
1133             KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
1134         }
1135         else if (KeBugCheckOwnerRecursionCount > 2)
1136         {
1137             /* Halt execution */
1138             while (TRUE);
1139         }
1140     }
1141 
1142     /* Call the Callbacks */
1143     KiDoBugCheckCallbacks();
1144 
1145     /* FIXME: Call Watchdog if enabled */
1146 
1147     /* Check if we have to reboot */
1148     if (Reboot)
1149     {
1150         /* Unload symbols */
1151         DbgUnLoadImageSymbols(NULL, (PVOID)MAXULONG_PTR, 0);
1152         HalReturnToFirmware(HalRebootRoutine);
1153     }
1154 
1155     /* Attempt to break in the debugger (otherwise halt CPU) */
1156     KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
1157 
1158     /* Shouldn't get here */
1159     ASSERT(FALSE);
1160     while (TRUE);
1161 }
1162 
1163 BOOLEAN
1164 NTAPI
KiHandleNmi(VOID)1165 KiHandleNmi(VOID)
1166 {
1167     BOOLEAN Handled = FALSE;
1168     PKNMI_HANDLER_CALLBACK NmiData;
1169 
1170     /* Parse the list of callbacks */
1171     NmiData = KiNmiCallbackListHead;
1172     while (NmiData)
1173     {
1174         /* Save if this callback has handled it -- all it takes is one */
1175         Handled |= NmiData->Callback(NmiData->Context, Handled);
1176         NmiData = NmiData->Next;
1177     }
1178 
1179     /* Has anyone handled this? */
1180     return Handled;
1181 }
1182 
1183 /* PUBLIC FUNCTIONS **********************************************************/
1184 
1185 /*
1186  * @unimplemented
1187  */
1188 NTSTATUS
1189 NTAPI
KeInitializeCrashDumpHeader(IN ULONG Type,IN ULONG Flags,OUT PVOID Buffer,IN ULONG BufferSize,OUT ULONG BufferNeeded OPTIONAL)1190 KeInitializeCrashDumpHeader(IN ULONG Type,
1191                             IN ULONG Flags,
1192                             OUT PVOID Buffer,
1193                             IN ULONG BufferSize,
1194                             OUT ULONG BufferNeeded OPTIONAL)
1195 {
1196     UNIMPLEMENTED;
1197     return STATUS_UNSUCCESSFUL;
1198 }
1199 
1200 /*
1201  * @implemented
1202  */
1203 BOOLEAN
1204 NTAPI
KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)1205 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)
1206 {
1207     KIRQL OldIrql;
1208     BOOLEAN Status = FALSE;
1209 
1210     /* Raise IRQL to High */
1211     KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1212 
1213     /* Check the Current State */
1214     if (CallbackRecord->State == BufferInserted)
1215     {
1216         /* Reset state and remove from list */
1217         CallbackRecord->State = BufferEmpty;
1218         RemoveEntryList(&CallbackRecord->Entry);
1219         Status = TRUE;
1220     }
1221 
1222     /* Lower IRQL and return */
1223     KeLowerIrql(OldIrql);
1224     return Status;
1225 }
1226 
1227 /*
1228  * @implemented
1229  */
1230 BOOLEAN
1231 NTAPI
KeDeregisterBugCheckReasonCallback(IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)1232 KeDeregisterBugCheckReasonCallback(
1233     IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)
1234 {
1235     KIRQL OldIrql;
1236     BOOLEAN Status = FALSE;
1237 
1238     /* Raise IRQL to High */
1239     KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1240 
1241     /* Check the Current State */
1242     if (CallbackRecord->State == BufferInserted)
1243     {
1244         /* Reset state and remove from list */
1245         CallbackRecord->State = BufferEmpty;
1246         RemoveEntryList(&CallbackRecord->Entry);
1247         Status = TRUE;
1248     }
1249 
1250     /* Lower IRQL and return */
1251     KeLowerIrql(OldIrql);
1252     return Status;
1253 }
1254 
1255 /*
1256  * @implemented
1257  */
1258 BOOLEAN
1259 NTAPI
KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,IN PVOID Buffer,IN ULONG Length,IN PUCHAR Component)1260 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
1261                            IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
1262                            IN PVOID Buffer,
1263                            IN ULONG Length,
1264                            IN PUCHAR Component)
1265 {
1266     KIRQL OldIrql;
1267     BOOLEAN Status = FALSE;
1268 
1269     /* Raise IRQL to High */
1270     KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1271 
1272     /* Check the Current State first so we don't double-register */
1273     if (CallbackRecord->State == BufferEmpty)
1274     {
1275         /* Set the Callback Settings and insert into the list */
1276         CallbackRecord->Length = Length;
1277         CallbackRecord->Buffer = Buffer;
1278         CallbackRecord->Component = Component;
1279         CallbackRecord->CallbackRoutine = CallbackRoutine;
1280         CallbackRecord->State = BufferInserted;
1281         InsertTailList(&KeBugcheckCallbackListHead, &CallbackRecord->Entry);
1282         Status = TRUE;
1283     }
1284 
1285     /* Lower IRQL and return */
1286     KeLowerIrql(OldIrql);
1287     return Status;
1288 }
1289 
1290 /*
1291  * @implemented
1292  */
1293 BOOLEAN
1294 NTAPI
KeRegisterBugCheckReasonCallback(IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,IN KBUGCHECK_CALLBACK_REASON Reason,IN PUCHAR Component)1295 KeRegisterBugCheckReasonCallback(
1296     IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
1297     IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
1298     IN KBUGCHECK_CALLBACK_REASON Reason,
1299     IN PUCHAR Component)
1300 {
1301     KIRQL OldIrql;
1302     BOOLEAN Status = FALSE;
1303 
1304     /* Raise IRQL to High */
1305     KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1306 
1307     /* Check the Current State first so we don't double-register */
1308     if (CallbackRecord->State == BufferEmpty)
1309     {
1310         /* Set the Callback Settings and insert into the list */
1311         CallbackRecord->Component = Component;
1312         CallbackRecord->CallbackRoutine = CallbackRoutine;
1313         CallbackRecord->State = BufferInserted;
1314         CallbackRecord->Reason = Reason;
1315         InsertTailList(&KeBugcheckReasonCallbackListHead,
1316                        &CallbackRecord->Entry);
1317         Status = TRUE;
1318     }
1319 
1320     /* Lower IRQL and return */
1321     KeLowerIrql(OldIrql);
1322     return Status;
1323 }
1324 
1325 /*
1326  * @implemented
1327  */
1328 PVOID
1329 NTAPI
KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine,IN PVOID Context)1330 KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine,
1331                       IN PVOID Context)
1332 {
1333     KIRQL OldIrql;
1334     PKNMI_HANDLER_CALLBACK NmiData, Next;
1335     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1336 
1337     /* Allocate NMI callback data */
1338     NmiData = ExAllocatePoolWithTag(NonPagedPool, sizeof(*NmiData), TAG_KNMI);
1339     if (!NmiData) return NULL;
1340 
1341     /* Fill in the information */
1342     NmiData->Callback = CallbackRoutine;
1343     NmiData->Context = Context;
1344     NmiData->Handle = NmiData;
1345 
1346     /* Insert it into NMI callback list */
1347     KiAcquireNmiListLock(&OldIrql);
1348     NmiData->Next = KiNmiCallbackListHead;
1349     Next = InterlockedCompareExchangePointer((PVOID*)&KiNmiCallbackListHead,
1350                                              NmiData,
1351                                              NmiData->Next);
1352     ASSERT(Next == NmiData->Next);
1353     KiReleaseNmiListLock(OldIrql);
1354 
1355     /* Return the opaque "handle" */
1356     return NmiData->Handle;
1357 }
1358 
1359 /*
1360  * @implemented
1361  */
1362 NTSTATUS
1363 NTAPI
KeDeregisterNmiCallback(IN PVOID Handle)1364 KeDeregisterNmiCallback(IN PVOID Handle)
1365 {
1366     KIRQL OldIrql;
1367     PKNMI_HANDLER_CALLBACK NmiData;
1368     PKNMI_HANDLER_CALLBACK* Previous;
1369     ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1370 
1371     /* Find in the list the NMI callback corresponding to the handle */
1372     KiAcquireNmiListLock(&OldIrql);
1373     Previous = &KiNmiCallbackListHead;
1374     NmiData = *Previous;
1375     while (NmiData)
1376     {
1377         if (NmiData->Handle == Handle)
1378         {
1379             /* The handle is the pointer to the callback itself */
1380             ASSERT(Handle == NmiData);
1381 
1382             /* Found it, remove from the list */
1383             *Previous = NmiData->Next;
1384             break;
1385         }
1386 
1387         /* Not found; try again */
1388         Previous = &NmiData->Next;
1389         NmiData = *Previous;
1390     }
1391     KiReleaseNmiListLock(OldIrql);
1392 
1393     /* If we have found the entry, free it */
1394     if (NmiData)
1395     {
1396         ExFreePoolWithTag(NmiData, TAG_KNMI);
1397         return STATUS_SUCCESS;
1398     }
1399 
1400     return STATUS_INVALID_HANDLE;
1401 }
1402 
1403 /*
1404  * @implemented
1405  */
1406 DECLSPEC_NORETURN
1407 VOID
1408 NTAPI
KeBugCheckEx(IN ULONG BugCheckCode,IN ULONG_PTR BugCheckParameter1,IN ULONG_PTR BugCheckParameter2,IN ULONG_PTR BugCheckParameter3,IN ULONG_PTR BugCheckParameter4)1409 KeBugCheckEx(IN ULONG BugCheckCode,
1410              IN ULONG_PTR BugCheckParameter1,
1411              IN ULONG_PTR BugCheckParameter2,
1412              IN ULONG_PTR BugCheckParameter3,
1413              IN ULONG_PTR BugCheckParameter4)
1414 {
1415     /* Call the internal API */
1416     KeBugCheckWithTf(BugCheckCode,
1417                      BugCheckParameter1,
1418                      BugCheckParameter2,
1419                      BugCheckParameter3,
1420                      BugCheckParameter4,
1421                      NULL);
1422 }
1423 
1424 /*
1425  * @implemented
1426  */
1427 DECLSPEC_NORETURN
1428 VOID
1429 NTAPI
KeBugCheck(ULONG BugCheckCode)1430 KeBugCheck(ULONG BugCheckCode)
1431 {
1432     /* Call the internal API */
1433     KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL);
1434 }
1435 
1436 /*
1437  * @implemented
1438  */
1439 VOID
1440 NTAPI
KeEnterKernelDebugger(VOID)1441 KeEnterKernelDebugger(VOID)
1442 {
1443     /* Disable interrupts */
1444     KiHardwareTrigger = 1;
1445     _disable();
1446 
1447     /* Check the bugcheck count */
1448     if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
1449     {
1450         /* There was only one, is the debugger disabled? */
1451         if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1452         {
1453             /* Enable the debugger */
1454             KdInitSystem(0, NULL);
1455         }
1456     }
1457 
1458     /* Break in the debugger */
1459     KiBugCheckDebugBreak(DBG_STATUS_FATAL);
1460 }
1461 
1462 /* EOF */
1463