284f4252ccd75cf8b9a733cfbf94778d755958d8
[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, 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 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 = (PCHAR)((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 /* Parse the list of callbacks */
1221 NmiData = KiNmiCallbackListHead;
1222 while (NmiData)
1223 {
1224 /* Save if this callback has handled it -- all it takes is one */
1225 Handled |= NmiData->Callback(NmiData->Context, Handled);
1226 NmiData = NmiData->Next;
1227 }
1228
1229 /* Has anyone handled this? */
1230 return Handled;
1231 }
1232
1233 /* PUBLIC FUNCTIONS **********************************************************/
1234
1235 /*
1236 * @unimplemented
1237 */
1238 NTSTATUS
1239 NTAPI
1240 KeInitializeCrashDumpHeader(IN ULONG Type,
1241 IN ULONG Flags,
1242 OUT PVOID Buffer,
1243 IN ULONG BufferSize,
1244 OUT ULONG BufferNeeded OPTIONAL)
1245 {
1246 UNIMPLEMENTED;
1247 return STATUS_UNSUCCESSFUL;
1248 }
1249
1250 /*
1251 * @implemented
1252 */
1253 BOOLEAN
1254 NTAPI
1255 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)
1256 {
1257 KIRQL OldIrql;
1258 BOOLEAN Status = FALSE;
1259
1260 /* Raise IRQL to High */
1261 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1262
1263 /* Check the Current State */
1264 if (CallbackRecord->State == BufferInserted)
1265 {
1266 /* Reset state and remove from list */
1267 CallbackRecord->State = BufferEmpty;
1268 RemoveEntryList(&CallbackRecord->Entry);
1269 Status = TRUE;
1270 }
1271
1272 /* Lower IRQL and return */
1273 KeLowerIrql(OldIrql);
1274 return Status;
1275 }
1276
1277 /*
1278 * @implemented
1279 */
1280 BOOLEAN
1281 NTAPI
1282 KeDeregisterBugCheckReasonCallback(
1283 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)
1284 {
1285 KIRQL OldIrql;
1286 BOOLEAN Status = FALSE;
1287
1288 /* Raise IRQL to High */
1289 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1290
1291 /* Check the Current State */
1292 if (CallbackRecord->State == BufferInserted)
1293 {
1294 /* Reset state and remove from list */
1295 CallbackRecord->State = BufferEmpty;
1296 RemoveEntryList(&CallbackRecord->Entry);
1297 Status = TRUE;
1298 }
1299
1300 /* Lower IRQL and return */
1301 KeLowerIrql(OldIrql);
1302 return Status;
1303 }
1304
1305 /*
1306 * @implemented
1307 */
1308 BOOLEAN
1309 NTAPI
1310 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
1311 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
1312 IN PVOID Buffer,
1313 IN ULONG Length,
1314 IN PUCHAR Component)
1315 {
1316 KIRQL OldIrql;
1317 BOOLEAN Status = FALSE;
1318
1319 /* Raise IRQL to High */
1320 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1321
1322 /* Check the Current State first so we don't double-register */
1323 if (CallbackRecord->State == BufferEmpty)
1324 {
1325 /* Set the Callback Settings and insert into the list */
1326 CallbackRecord->Length = Length;
1327 CallbackRecord->Buffer = Buffer;
1328 CallbackRecord->Component = Component;
1329 CallbackRecord->CallbackRoutine = CallbackRoutine;
1330 CallbackRecord->State = BufferInserted;
1331 InsertTailList(&KeBugcheckCallbackListHead, &CallbackRecord->Entry);
1332 Status = TRUE;
1333 }
1334
1335 /* Lower IRQL and return */
1336 KeLowerIrql(OldIrql);
1337 return Status;
1338 }
1339
1340 /*
1341 * @implemented
1342 */
1343 BOOLEAN
1344 NTAPI
1345 KeRegisterBugCheckReasonCallback(
1346 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
1347 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
1348 IN KBUGCHECK_CALLBACK_REASON Reason,
1349 IN PUCHAR Component)
1350 {
1351 KIRQL OldIrql;
1352 BOOLEAN Status = FALSE;
1353
1354 /* Raise IRQL to High */
1355 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1356
1357 /* Check the Current State first so we don't double-register */
1358 if (CallbackRecord->State == BufferEmpty)
1359 {
1360 /* Set the Callback Settings and insert into the list */
1361 CallbackRecord->Component = Component;
1362 CallbackRecord->CallbackRoutine = CallbackRoutine;
1363 CallbackRecord->State = BufferInserted;
1364 CallbackRecord->Reason = Reason;
1365 InsertTailList(&KeBugcheckReasonCallbackListHead,
1366 &CallbackRecord->Entry);
1367 Status = TRUE;
1368 }
1369
1370 /* Lower IRQL and return */
1371 KeLowerIrql(OldIrql);
1372 return Status;
1373 }
1374
1375 /*
1376 * @implemented
1377 */
1378 PVOID
1379 NTAPI
1380 KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine,
1381 IN PVOID Context)
1382 {
1383 KIRQL OldIrql;
1384 PKNMI_HANDLER_CALLBACK NmiData, Next;
1385 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
1386
1387 /* Allocate NMI callback data */
1388 NmiData = ExAllocatePoolWithTag(NonPagedPool,
1389 sizeof(KNMI_HANDLER_CALLBACK),
1390 'IMNK');
1391 if (!NmiData) return NULL;
1392
1393 /* Fill in the information */
1394 NmiData->Callback = CallbackRoutine;
1395 NmiData->Context = Context;
1396 NmiData->Handle = NmiData;
1397
1398 /* Insert it into NMI callback list */
1399 KiAcquireNmiListLock(&OldIrql);
1400 NmiData->Next = KiNmiCallbackListHead;
1401 Next = InterlockedCompareExchangePointer((PVOID*)&KiNmiCallbackListHead,
1402 NmiData,
1403 NmiData->Next);
1404 ASSERT(Next == NmiData->Next);
1405 KiReleaseNmiListLock(OldIrql);
1406
1407 /* Return the opaque "handle" */
1408 return NmiData->Handle;
1409 }
1410
1411 /*
1412 * @implemented
1413 */
1414 NTSTATUS
1415 NTAPI
1416 KeDeregisterNmiCallback(PVOID Handle)
1417 {
1418 UNIMPLEMENTED;
1419 return STATUS_UNSUCCESSFUL;
1420 }
1421
1422 /*
1423 * @implemented
1424 */
1425 VOID
1426 NTAPI
1427 KeBugCheckEx(IN ULONG BugCheckCode,
1428 IN ULONG_PTR BugCheckParameter1,
1429 IN ULONG_PTR BugCheckParameter2,
1430 IN ULONG_PTR BugCheckParameter3,
1431 IN ULONG_PTR BugCheckParameter4)
1432 {
1433 /* Workaround for Windows Server 2003 Checked PCI Driver issue */
1434 if (!((BugCheckCode == PCI_BUS_DRIVER_INTERNAL) &&
1435 (BugCheckParameter1 == 0xDEAD0010)))
1436 {
1437 /* Call the internal API */
1438 KeBugCheckWithTf(BugCheckCode,
1439 BugCheckParameter1,
1440 BugCheckParameter2,
1441 BugCheckParameter3,
1442 BugCheckParameter4,
1443 NULL);
1444 }
1445 }
1446
1447 /*
1448 * @implemented
1449 */
1450 VOID
1451 NTAPI
1452 KeBugCheck(ULONG BugCheckCode)
1453 {
1454 /* Call the internal API */
1455 KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL);
1456 }
1457
1458 /*
1459 * @implemented
1460 */
1461 VOID
1462 NTAPI
1463 KeEnterKernelDebugger(VOID)
1464 {
1465 /* Disable interrupts */
1466 KiHardwareTrigger = 1;
1467 _disable();
1468
1469 /* Check the bugcheck count */
1470 if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
1471 {
1472 /* There was only one, is the debugger disabled? */
1473 if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1474 {
1475 /* Enable the debugger */
1476 KdInitSystem(0, NULL);
1477 }
1478 }
1479
1480 /* Break in the debugger */
1481 KiBugCheckDebugBreak(DBG_STATUS_FATAL);
1482 }
1483
1484 /* EOF */