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