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