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