- Change CPUID to match the old Ki386Cpuid and take 4 output arguments instead of...
[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 Eip,
41 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry,
42 IN BOOLEAN DriversOnly,
43 OUT PBOOLEAN InKernel)
44 {
45 ULONG i = 0;
46 PVOID ImageBase, EipBase = 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)Eip >= (ULONG_PTR)Entry->DllBase) &&
86 ((ULONG_PTR)Eip < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
87 {
88 /* Return this entry */
89 *LdrEntry = Entry;
90 EipBase = 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 EipBase;
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 Eip,
142 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
143 {
144 PVOID ImageBase, EipBase = 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)Eip >= (ULONG_PTR)Entry->DllBase) &&
174 ((ULONG_PTR)Eip < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
175 {
176 /* Return this entry */
177 *LdrEntry = Entry;
178 EipBase = ImageBase;
179 break;
180 }
181 }
182 }
183
184 /* Return the base address */
185 return EipBase;
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 DECLSPEC_NORETURN
550 VOID
551 NTAPI
552 KiBugCheckDebugBreak(IN ULONG StatusCode)
553 {
554 /* If KDBG isn't connected, freeze the CPU, otherwise, break */
555 #if defined(_M_IX86) || defined(_M_AMD64)
556 if (KdDebuggerNotPresent) for (;;) __halt();
557 #elif defined(_M_ARM)
558 if (KdDebuggerNotPresent) for (;;) KeArmHaltProcessor();
559 #else
560 #error
561 #endif
562 DbgBreakPointWithStatus(StatusCode);
563 while (TRUE);
564 }
565
566 PCHAR
567 NTAPI
568 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode,
569 OUT PCHAR Ansi,
570 IN ULONG Length)
571 {
572 PCHAR p;
573 PWCHAR pw;
574 ULONG i;
575
576 /* Set length and normalize it */
577 i = Unicode->Length / sizeof(WCHAR);
578 i = min(i, Length - 1);
579
580 /* Set source and destination, and copy */
581 pw = Unicode->Buffer;
582 p = Ansi;
583 while (i--) *p++ = (CHAR)*pw++;
584
585 /* Null terminate and return */
586 *p = ANSI_NULL;
587 return Ansi;
588 }
589
590 VOID
591 NTAPI
592 KiDumpParameterImages(IN PCHAR Message,
593 IN PULONG_PTR Parameters,
594 IN ULONG ParameterCount,
595 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine)
596 {
597 ULONG i;
598 BOOLEAN InSystem;
599 PLDR_DATA_TABLE_ENTRY LdrEntry;
600 PVOID ImageBase;
601 PUNICODE_STRING DriverName;
602 CHAR AnsiName[32];
603 PIMAGE_NT_HEADERS NtHeader;
604 ULONG TimeStamp;
605 BOOLEAN FirstRun = TRUE;
606
607 /* Loop parameters */
608 for (i = 0; i < ParameterCount; i++)
609 {
610 /* Get the base for this parameter */
611 ImageBase = KiPcToFileHeader((PVOID)Parameters[i],
612 &LdrEntry,
613 FALSE,
614 &InSystem);
615 if (!ImageBase)
616 {
617 /* FIXME: Add code to check for unloaded drivers */
618 DPRINT1("Potentially unloaded driver!\n");
619 continue;
620 }
621 else
622 {
623 /* Get the NT Headers and Timestamp */
624 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
625 TimeStamp = NtHeader->FileHeader.TimeDateStamp;
626
627 /* Convert the driver name */
628 DriverName = &LdrEntry->BaseDllName;
629 ConversionRoutine(&LdrEntry->BaseDllName,
630 AnsiName,
631 sizeof(AnsiName));
632 }
633
634 /* Format driver name */
635 sprintf(Message,
636 "%s** %12s - Address %p base at %p, DateStamp %08lx\n",
637 FirstRun ? "\r\n*":"*",
638 AnsiName,
639 (PVOID)Parameters[i],
640 ImageBase,
641 TimeStamp);
642
643 /* Check if we only had one parameter */
644 if (ParameterCount <= 1)
645 {
646 /* Then just save the name */
647 KiBugCheckDriver = DriverName;
648 }
649 else
650 {
651 /* Otherwise, display the message */
652 InbvDisplayString(Message);
653 }
654
655 /* Loop again */
656 FirstRun = FALSE;
657 }
658 }
659
660 VOID
661 NTAPI
662 KiDisplayBlueScreen(IN ULONG MessageId,
663 IN BOOLEAN IsHardError,
664 IN PCHAR HardErrCaption OPTIONAL,
665 IN PCHAR HardErrMessage OPTIONAL,
666 IN PCHAR Message)
667 {
668 CHAR AnsiName[75];
669
670 /* Check if bootvid is installed */
671 if (InbvIsBootDriverInstalled())
672 {
673 /* Acquire ownership and reset the display */
674 InbvAcquireDisplayOwnership();
675 InbvResetDisplay();
676
677 /* Display blue screen */
678 InbvSolidColorFill(0, 0, 639, 479, 4);
679 InbvSetTextColor(15);
680 InbvInstallDisplayStringFilter(NULL);
681 InbvEnableDisplayString(TRUE);
682 InbvSetScrollRegion(0, 0, 639, 479);
683 }
684
685 /* Check if this is a hard error */
686 if (IsHardError)
687 {
688 /* Display caption and message */
689 if (HardErrCaption) InbvDisplayString(HardErrCaption);
690 if (HardErrMessage) InbvDisplayString(HardErrMessage);
691 }
692
693 /* Begin the display */
694 InbvDisplayString("\r\n");
695
696 /* Print out initial message */
697 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL);
698 InbvDisplayString("\r\n\r\n");
699
700 /* Check if we have a driver */
701 if (KiBugCheckDriver)
702 {
703 /* Print out into to driver name */
704 KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
705
706 /* Convert and print out driver name */
707 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
708 InbvDisplayString(" ");
709 InbvDisplayString(AnsiName);
710 InbvDisplayString("\r\n\r\n");
711 }
712
713 /* Check if this is the generic message */
714 if (MessageId == BUGCODE_PSS_MESSAGE)
715 {
716 /* It is, so get the bug code string as well */
717 KeGetBugMessageText(KiBugCheckData[0], NULL);
718 InbvDisplayString("\r\n\r\n");
719 }
720
721 /* Print second introduction message */
722 KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL);
723 InbvDisplayString("\r\n\r\n");
724
725 /* Get the bug code string */
726 KeGetBugMessageText(MessageId, NULL);
727 InbvDisplayString("\r\n\r\n");
728
729 /* Print message for technical information */
730 KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
731
732 /* Show the technical Data */
733 sprintf(AnsiName,
734 "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
735 KiBugCheckData[0],
736 (PVOID)KiBugCheckData[1],
737 (PVOID)KiBugCheckData[2],
738 (PVOID)KiBugCheckData[3],
739 (PVOID)KiBugCheckData[4]);
740 InbvDisplayString(AnsiName);
741
742 /* Check if we have a driver*/
743 if (KiBugCheckDriver)
744 {
745 /* Display technical driver data */
746 InbvDisplayString(Message);
747 }
748 else
749 {
750 /* Dump parameter information */
751 KiDumpParameterImages(Message,
752 (PVOID)&KiBugCheckData[1],
753 4,
754 KeBugCheckUnicodeToAnsi);
755 }
756 }
757
758 VOID
759 NTAPI
760 KeBugCheckWithTf(IN ULONG BugCheckCode,
761 IN ULONG_PTR BugCheckParameter1,
762 IN ULONG_PTR BugCheckParameter2,
763 IN ULONG_PTR BugCheckParameter3,
764 IN ULONG_PTR BugCheckParameter4,
765 IN PKTRAP_FRAME TrapFrame)
766 {
767 PKPRCB Prcb = KeGetCurrentPrcb();
768 CONTEXT Context;
769 ULONG MessageId;
770 CHAR AnsiName[128];
771 BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE;
772 PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
773 PVOID Eip = NULL, Memory;
774 PVOID DriverBase;
775 PLDR_DATA_TABLE_ENTRY LdrEntry;
776 PULONG_PTR HardErrorParameters;
777 KIRQL OldIrql;
778 #ifdef CONFIG_SMP
779 LONG i = 0;
780 #endif
781
782 /* Set active bugcheck */
783 KeBugCheckActive = TRUE;
784 KiBugCheckDriver = NULL;
785
786 /* Check if this is power failure simulation */
787 if (BugCheckCode == POWER_FAILURE_SIMULATE)
788 {
789 /* Call the Callbacks and reboot */;
790 KiDoBugCheckCallbacks();
791 HalReturnToFirmware(HalRebootRoutine);
792 }
793
794 /* Save the IRQL and set hardware trigger */
795 Prcb->DebuggerSavedIRQL = KeGetCurrentIrql();
796 InterlockedIncrement((PLONG)&KiHardwareTrigger);
797
798 /* Capture the CPU Context */
799 RtlCaptureContext(&Prcb->ProcessorState.ContextFrame);
800 KiSaveProcessorControlState(&Prcb->ProcessorState);
801 Context = Prcb->ProcessorState.ContextFrame;
802
803 /* FIXME: Call the Watchdog if it's registered */
804
805 /* Check which bugcode this is */
806 switch (BugCheckCode)
807 {
808 /* These bug checks already have detailed messages, keep them */
809 case UNEXPECTED_KERNEL_MODE_TRAP:
810 case DRIVER_CORRUPTED_EXPOOL:
811 case ACPI_BIOS_ERROR:
812 case ACPI_BIOS_FATAL_ERROR:
813 case THREAD_STUCK_IN_DEVICE_DRIVER:
814 case DATA_BUS_ERROR:
815 case FAT_FILE_SYSTEM:
816 case NO_MORE_SYSTEM_PTES:
817 case INACCESSIBLE_BOOT_DEVICE:
818
819 /* Keep the same code */
820 MessageId = BugCheckCode;
821 break;
822
823 /* Check if this is a kernel-mode exception */
824 case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
825 //case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED:
826 case KMODE_EXCEPTION_NOT_HANDLED:
827
828 /* Use the generic text message */
829 MessageId = KMODE_EXCEPTION_NOT_HANDLED;
830 break;
831
832 /* File-system errors */
833 case NTFS_FILE_SYSTEM:
834
835 /* Use the generic message for FAT */
836 MessageId = FAT_FILE_SYSTEM;
837 break;
838
839 /* Check if this is a coruption of the Mm's Pool */
840 case DRIVER_CORRUPTED_MMPOOL:
841
842 /* Use generic corruption message */
843 MessageId = DRIVER_CORRUPTED_EXPOOL;
844 break;
845
846 /* Check if this is a signature check failure */
847 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
848
849 /* Use the generic corruption message */
850 MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE;
851 break;
852
853 /* All other codes */
854 default:
855
856 /* Use the default bugcheck message */
857 MessageId = BUGCODE_PSS_MESSAGE;
858 break;
859 }
860
861 /* Save bugcheck data */
862 KiBugCheckData[0] = BugCheckCode;
863 KiBugCheckData[1] = BugCheckParameter1;
864 KiBugCheckData[2] = BugCheckParameter2;
865 KiBugCheckData[3] = BugCheckParameter3;
866 KiBugCheckData[4] = BugCheckParameter4;
867
868 /* Now check what bugcheck this is */
869 switch (BugCheckCode)
870 {
871 /* Invalid access to R/O memory or Unhandled KM Exception */
872 case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
873 case ATTEMPTED_WRITE_TO_READONLY_MEMORY:
874 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY:
875
876 /* Check if we have a trap frame */
877 if (!TrapFrame)
878 {
879 /* Use parameter 3 as a trap frame, if it exists */
880 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
881 }
882
883 /* Check if we got one now and if we need to get EIP */
884 if ((TrapFrame) &&
885 (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
886 {
887 #ifdef _M_IX86
888 /* Get EIP */
889 Eip = (PVOID)TrapFrame->Eip;
890 #elif defined(_M_PPC)
891 Eip = (PVOID)TrapFrame->Dr0; /* srr0 */
892 #endif
893 }
894 break;
895
896 /* Wrong IRQL */
897 case IRQL_NOT_LESS_OR_EQUAL:
898
899 /*
900 * The NT kernel has 3 special sections:
901 * MISYSPTE, POOLMI and POOLCODE. The bug check code can
902 * determine in which of these sections this bugcode happened
903 * and provide a more detailed analysis. For now, we don't.
904 */
905
906 /* Eip is in parameter 4 */
907 Eip = (PVOID)BugCheckParameter4;
908
909 /* Get the driver base */
910 DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
911 if (IsSystem)
912 {
913 /*
914 * The error happened inside the kernel or HAL.
915 * Get the memory address that was being referenced.
916 */
917 Memory = (PVOID)BugCheckParameter1;
918
919 /* Find to which driver it belongs */
920 DriverBase = KiPcToFileHeader(Memory,
921 &LdrEntry,
922 TRUE,
923 &IsSystem);
924 if (DriverBase)
925 {
926 /* Get the driver name and update the bug code */
927 KiBugCheckDriver = &LdrEntry->BaseDllName;
928 KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED;
929 }
930 else
931 {
932 /* Find the driver that unloaded at this address */
933 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
934
935 /* Check if the cause was an unloaded driver */
936 if (KiBugCheckDriver)
937 {
938 /* Update bug check code */
939 KiBugCheckData[0] =
940 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD;
941 }
942 }
943 }
944 else
945 {
946 /* Update the bug check code */
947 KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
948 }
949
950 /* Clear EIP so we don't look it up later */
951 Eip = NULL;
952 break;
953
954 /* Hard error */
955 case FATAL_UNHANDLED_HARD_ERROR:
956
957 /* Copy bug check data from hard error */
958 HardErrorParameters = (PULONG_PTR)BugCheckParameter2;
959 KiBugCheckData[0] = BugCheckParameter1;
960 KiBugCheckData[1] = HardErrorParameters[0];
961 KiBugCheckData[2] = HardErrorParameters[1];
962 KiBugCheckData[3] = HardErrorParameters[2];
963 KiBugCheckData[4] = HardErrorParameters[3];
964
965 /* Remember that this is hard error and set the caption/message */
966 IsHardError = TRUE;
967 HardErrCaption = (PCHAR)BugCheckParameter3;
968 HardErrMessage = (PCHAR)BugCheckParameter4;
969 break;
970
971 /* Page fault */
972 case PAGE_FAULT_IN_NONPAGED_AREA:
973
974 /* Assume no driver */
975 DriverBase = NULL;
976
977 /* Check if we have a trap frame */
978 if (!TrapFrame)
979 {
980 /* We don't, use parameter 3 if possible */
981 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
982 }
983
984 /* Check if we have a frame now */
985 if (TrapFrame)
986 {
987 #ifdef _M_IX86
988 /* Get EIP */
989 Eip = (PVOID)TrapFrame->Eip;
990 KiBugCheckData[3] = (ULONG)Eip;
991 #elif defined(_M_PPC)
992 Eip = (PVOID)TrapFrame->Dr0; /* srr0 */
993 KiBugCheckData[3] = (ULONG)Eip;
994 #endif
995
996 /* Find out if was in the kernel or drivers */
997 DriverBase = KiPcToFileHeader(Eip,
998 &LdrEntry,
999 FALSE,
1000 &IsSystem);
1001 }
1002
1003 /*
1004 * Now we should check if this happened in:
1005 * 1) Special Pool 2) Free Special Pool 3) Session Pool
1006 * and update the bugcheck code appropriately.
1007 */
1008
1009 /* Check if we didn't have a driver base */
1010 if (!DriverBase)
1011 {
1012 /* Find the driver that unloaded at this address */
1013 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
1014
1015 /* Check if the cause was an unloaded driver */
1016 if (KiBugCheckDriver)
1017 {
1018 KiBugCheckData[0] =
1019 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS;
1020 }
1021 }
1022 break;
1023
1024 /* Check if the driver forgot to unlock pages */
1025 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
1026
1027 /* EIP is in parameter 1 */
1028 Eip = (PVOID)BugCheckParameter1;
1029 break;
1030
1031 /* Check if the driver consumed too many PTEs */
1032 case DRIVER_USED_EXCESSIVE_PTES:
1033
1034 /* Loader entry is in parameter 1 */
1035 LdrEntry = (PVOID)BugCheckParameter1;
1036 KiBugCheckDriver = &LdrEntry->BaseDllName;
1037 break;
1038
1039 /* Check if the driver has a stuck thread */
1040 case THREAD_STUCK_IN_DEVICE_DRIVER:
1041
1042 /* The name is in Parameter 3 */
1043 KiBugCheckDriver = (PVOID)BugCheckParameter3;
1044 break;
1045
1046 /* Anything else */
1047 default:
1048 break;
1049 }
1050
1051 /* Do we have a driver name? */
1052 if (KiBugCheckDriver)
1053 {
1054 /* Convert it to ANSI */
1055 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
1056 }
1057 else
1058 {
1059 /* Do we have an EIP? */
1060 if (Eip)
1061 {
1062 /* Dump image name */
1063 KiDumpParameterImages(AnsiName,
1064 (PULONG_PTR)&Eip,
1065 1,
1066 KeBugCheckUnicodeToAnsi);
1067 }
1068 }
1069
1070 /* Check if we need to save the context for KD */
1071 #ifdef _WINKD_
1072 if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG)&Context;
1073 #endif
1074
1075 /* Check if a debugger is connected */
1076 if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
1077 {
1078 /* Crash on the debugger console */
1079 DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
1080 " (0x%p,0x%p,0x%p,0x%p)\n\n",
1081 KiBugCheckData[0],
1082 KiBugCheckData[1],
1083 KiBugCheckData[2],
1084 KiBugCheckData[3],
1085 KiBugCheckData[4]);
1086
1087 /* Check if the debugger isn't currently connected */
1088 if (!KdDebuggerNotPresent)
1089 {
1090 /* Check if we have a driver to blame */
1091 if (KiBugCheckDriver)
1092 {
1093 /* Dump it */
1094 DbgPrint("Driver at fault: %s.\n", AnsiName);
1095 }
1096
1097 /* Check if this was a hard error */
1098 if (IsHardError)
1099 {
1100 /* Print caption and message */
1101 if (HardErrCaption) DbgPrint(HardErrCaption);
1102 if (HardErrMessage) DbgPrint(HardErrMessage);
1103 }
1104
1105 /* Break in the debugger */
1106 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST);
1107 }
1108 else
1109 {
1110 /*
1111 * ROS HACK.
1112 * Ok, so debugging is enabled, but KDBG isn't there.
1113 * We'll manually dump the stack for the user.
1114 */
1115 KeRosDumpStackFrames(NULL, 0);
1116
1117 /* ROS HACK 2: Generate something useful for Bugzilla */
1118 KeRosDumpTriageForBugZillaReport();
1119 }
1120 }
1121
1122 /* Raise IRQL to HIGH_LEVEL */
1123 _disable();
1124 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1125
1126 /* Avoid recursion */
1127 if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
1128 {
1129 #ifdef CONFIG_SMP
1130 /* Set CPU that is bug checking now */
1131 KeBugCheckOwner = Prcb->Number;
1132
1133 /* Freeze the other CPUs */
1134 for (i = 0; i < KeNumberProcessors; i++)
1135 {
1136 if (i != (LONG)KeGetCurrentProcessorNumber())
1137 {
1138 /* Send the IPI and give them one second to catch up */
1139 KiIpiSend(1 << i, IPI_FREEZE);
1140 KeStallExecutionProcessor(1000000);
1141 }
1142 }
1143 #endif
1144
1145 /* Display the BSOD */
1146 KiDisplayBlueScreen(MessageId,
1147 IsHardError,
1148 HardErrCaption,
1149 HardErrMessage,
1150 AnsiName);
1151
1152 /* Check if the debugger is disabled but we can enable it */
1153 if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1154 {
1155 /* Enable it */
1156 #ifdef _WINKD_
1157 KdEnableDebuggerWithLock(FALSE);
1158 #endif
1159 }
1160 else
1161 {
1162 /* Otherwise, print the last line */
1163 InbvDisplayString("\r\n");
1164 }
1165
1166 /* Save the context */
1167 Prcb->ProcessorState.ContextFrame = Context;
1168
1169 /* FIXME: Support Triage Dump */
1170
1171 /* FIXME: Write the crash dump */
1172 }
1173 else
1174 {
1175 /* Increase recursion count */
1176 KeBugCheckOwnerRecursionCount++;
1177 if (KeBugCheckOwnerRecursionCount == 2)
1178 {
1179 /* Break in the debugger */
1180 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
1181 }
1182 else if (KeBugCheckOwnerRecursionCount > 2)
1183 {
1184 /* Halt the CPU */
1185 #if defined(_M_IX86) || defined(_M_AMD64)
1186 for (;;) __halt();
1187 #elif defined(_M_ARM)
1188 for (;;) KeArmHaltProcessor();
1189 #else
1190 #error
1191 #endif
1192 }
1193 }
1194
1195 /* Call the Callbacks */
1196 KiDoBugCheckCallbacks();
1197
1198 /* FIXME: Call Watchdog if enabled */
1199
1200 /* Check if we have to reboot */
1201 if (Reboot)
1202 {
1203 /* Unload symbols */
1204 DbgUnLoadImageSymbols(NULL, NtCurrentProcess(), 0);
1205 HalReturnToFirmware(HalRebootRoutine);
1206 }
1207
1208 /* Attempt to break in the debugger (otherwise halt CPU) */
1209 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
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 /* Bugcheck */
1431 KiBugCheckDebugBreak(DBG_STATUS_FATAL);
1432 }
1433
1434 /* EOF */