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