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