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