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