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