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