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