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