Partially fixed up tree after merge from HEAD. More to do.
[reactos.git] / reactos / ntoskrnl / ke / bug.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ke/bug.c
5 * PURPOSE: Bugcheck Support
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <internal/debug.h>
14
15 #if defined (ALLOC_PRAGMA)
16 #pragma alloc_text(INIT, KiInitializeBugCheck)
17 #endif
18
19 /* ROS Internal. Please deprecate */
20 NTHALAPI
21 VOID
22 NTAPI
23 HalReleaseDisplayOwnership(
24 VOID
25 );
26
27 /* GLOBALS *******************************************************************/
28
29 LIST_ENTRY BugcheckCallbackListHead;
30 LIST_ENTRY BugcheckReasonCallbackListHead;
31 KSPIN_LOCK BugCheckCallbackLock;
32 ULONG KeBugCheckActive, KeBugCheckOwner;
33 LONG KeBugCheckOwnerRecursionCount;
34 PRTL_MESSAGE_RESOURCE_DATA KiBugCodeMessages;
35 ULONG KeBugCheckCount = 1;
36 ULONG KiHardwareTrigger;
37 PUNICODE_STRING KiBugCheckDriver;
38 ULONG_PTR KiBugCheckData[5];
39
40 /* PRIVATE FUNCTIONS *********************************************************/
41
42 BOOLEAN
43 NTAPI
44 KiRosPrintAddress(PVOID address)
45 {
46 PLIST_ENTRY current_entry;
47 PLDR_DATA_TABLE_ENTRY current;
48 extern LIST_ENTRY ModuleListHead;
49 ULONG_PTR RelativeAddress;
50 ULONG i = 0;
51
52 do
53 {
54 current_entry = ModuleListHead.Flink;
55
56 while (current_entry != &ModuleListHead)
57 {
58 current = CONTAINING_RECORD(current_entry,
59 LDR_DATA_TABLE_ENTRY,
60 InLoadOrderLinks);
61
62 if (address >= (PVOID)current->DllBase &&
63 address < (PVOID)((ULONG_PTR)current->DllBase +
64 current->SizeOfImage))
65 {
66 RelativeAddress = (ULONG_PTR)address -
67 (ULONG_PTR)current->DllBase;
68 DbgPrint("<%wZ: %x>", &current->FullDllName, RelativeAddress);
69 return(TRUE);
70 }
71 current_entry = current_entry->Flink;
72 }
73 } while(++i <= 1);
74
75 return(FALSE);
76 }
77
78 VOID
79 NTAPI
80 KeRosDumpStackFrames(IN PULONG Frame OPTIONAL,
81 IN ULONG FrameCount OPTIONAL)
82 {
83 ULONG Frames[32];
84 ULONG i, Addr;
85
86 /* If the caller didn't ask, assume 32 frames */
87 if (!FrameCount) FrameCount = 32;
88
89 /* Get the current frames */
90 FrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL);
91
92 /* Now loop them (skip the two. One for the dumper, one for the caller) */
93 for (i = 0; i < FrameCount; i++)
94 {
95 /* Get the EIP */
96 Addr = Frames[i];
97
98 /* If we had a custom frame, make sure we've reached it first */
99 if ((Frame) && (Frame[1] == Addr))
100 {
101 Frame = NULL;
102 }
103 else if (Frame)
104 {
105 /* Skip this entry */
106 continue;
107 }
108
109 /* Print it out */
110 if (!KeRosPrintAddress((PVOID)Addr)) DbgPrint("<%X>", Addr);
111
112 /* Go to the next frame */
113 DbgPrint("\n");
114 }
115
116 /* Finish the output */
117 DbgPrint("\n");
118 }
119
120 VOID
121 INIT_FUNCTION
122 NTAPI
123 KiInitializeBugCheck(VOID)
124 {
125 PRTL_MESSAGE_RESOURCE_DATA BugCheckData;
126 LDR_RESOURCE_INFO ResourceInfo;
127 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
128 NTSTATUS Status;
129
130 /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
131 ResourceInfo.Type = 11;
132 ResourceInfo.Name = 1;
133 ResourceInfo.Language = 9;
134
135 /* Do the lookup. */
136 Status = LdrFindResource_U((PVOID)KERNEL_BASE,
137 &ResourceInfo,
138 RESOURCE_DATA_LEVEL,
139 &ResourceDataEntry);
140
141 /* Make sure it worked */
142 if (NT_SUCCESS(Status))
143 {
144 /* Now actually get a pointer to it */
145 Status = LdrAccessResource((PVOID)KERNEL_BASE,
146 ResourceDataEntry,
147 (PVOID*)&BugCheckData,
148 NULL);
149 if (NT_SUCCESS(Status)) KiBugCodeMessages = BugCheckData;
150 }
151 }
152
153 VOID
154 NTAPI
155 KeGetBugMessageText(IN ULONG BugCheckCode,
156 OUT PANSI_STRING OutputString OPTIONAL)
157 {
158 ULONG i;
159 ULONG IdOffset;
160 ULONG_PTR MessageEntry;
161 PCHAR BugCode;
162
163 /* Find the message. This code is based on RtlFindMesssage */
164 for (i = 0; i < KiBugCodeMessages->NumberOfBlocks; i++)
165 {
166 /* Check if the ID Matches */
167 if ((BugCheckCode >= KiBugCodeMessages->Blocks[i].LowId) &&
168 (BugCheckCode <= KiBugCodeMessages->Blocks[i].HighId))
169 {
170 /* Get Offset to Entry */
171 MessageEntry = KiBugCodeMessages->Blocks[i].OffsetToEntries +
172 (ULONG_PTR)KiBugCodeMessages;
173 IdOffset = BugCheckCode - KiBugCodeMessages->Blocks[i].LowId;
174
175 /* Get offset to ID */
176 for (i = 0; i < IdOffset; i++)
177 {
178 /* Advance in the Entries */
179 MessageEntry += ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->
180 Length;
181 }
182
183 /* Get the final Code */
184 BugCode = ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->Text;
185 i = strlen(BugCode);
186
187 /* Return it in the OutputString */
188 if (OutputString)
189 {
190 OutputString->Buffer = BugCode;
191 OutputString->Length = i + 1;
192 OutputString->MaximumLength = i + 1;
193 }
194 else
195 {
196 /* Direct Output to Screen */
197 InbvDisplayString(BugCode);
198 InbvDisplayString("\r");
199 break;
200 }
201 }
202 }
203 }
204
205 VOID
206 NTAPI
207 KiDoBugCheckCallbacks(VOID)
208 {
209 PKBUGCHECK_CALLBACK_RECORD CurrentRecord;
210 PLIST_ENTRY ListHead, NextEntry, LastEntry;
211 ULONG_PTR Checksum;
212
213 /* First make sure that the list is Initialized... it might not be */
214 ListHead = &BugcheckCallbackListHead;
215 if ((ListHead->Flink) && (ListHead->Blink))
216 {
217 /* Loop the list */
218 LastEntry = ListHead;
219 NextEntry = ListHead->Flink;
220 while (NextEntry != ListHead)
221 {
222 /* Get the reord */
223 CurrentRecord = CONTAINING_RECORD(NextEntry,
224 KBUGCHECK_CALLBACK_RECORD,
225 Entry);
226
227 /* Validate it */
228 if (CurrentRecord->Entry.Blink != LastEntry) return;
229 Checksum = (ULONG_PTR)CurrentRecord->CallbackRoutine;
230 Checksum += (ULONG_PTR)CurrentRecord->Buffer;
231 Checksum += (ULONG_PTR)CurrentRecord->Length;
232 Checksum += (ULONG_PTR)CurrentRecord->Component;
233
234 /* Make sure it's inserted and valitdated */
235 if ((CurrentRecord->State == BufferInserted) &&
236 (CurrentRecord->Checksum == Checksum))
237 {
238 /* Call the routine */
239 CurrentRecord->State = BufferStarted;
240 (CurrentRecord->CallbackRoutine)(CurrentRecord->Buffer,
241 CurrentRecord->Length);
242 CurrentRecord->State = BufferFinished;
243 }
244
245 /* Go to the next entry */
246 LastEntry = NextEntry;
247 NextEntry = NextEntry->Flink;
248 }
249 }
250 }
251
252 VOID
253 NTAPI
254 KiBugCheckDebugBreak(IN ULONG StatusCode)
255 {
256 /* If KDBG isn't connected, freeze the CPU, otherwise, break */
257 if (KdDebuggerNotPresent) for (;;) KeHaltProcessor();
258 DbgBreakPointWithStatus(StatusCode);
259 }
260
261 PVOID
262 NTAPI
263 KiPcToFileHeader(IN PVOID Eip,
264 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry,
265 IN BOOLEAN DriversOnly,
266 OUT PBOOLEAN InKernel)
267 {
268 #ifdef _M_IX86
269 ULONG i = 0;
270 PVOID ImageBase, EipBase = NULL;
271 PLDR_DATA_TABLE_ENTRY Entry;
272 PLIST_ENTRY ListHead, NextEntry;
273 extern LIST_ENTRY ModuleListHead;
274
275 /* Assume no */
276 *InKernel = FALSE;
277
278 /* Set list pointers and make sure it's valid */
279 ListHead = &ModuleListHead;
280 NextEntry = ListHead->Flink;
281 if (NextEntry)
282 {
283 /* Start loop */
284 while (NextEntry != ListHead)
285 {
286 /* Increase entry */
287 i++;
288
289 /* Check if this is a kernel entry and we only want drivers */
290 if ((i <= 2) && (DriversOnly == TRUE))
291 {
292 /* Skip it */
293 NextEntry = NextEntry->Flink;
294 continue;
295 }
296
297 /* Get the loader entry */
298 Entry = CONTAINING_RECORD(NextEntry,
299 LDR_DATA_TABLE_ENTRY,
300 InLoadOrderLinks);
301
302 /* Move to the next entry */
303 NextEntry = NextEntry->Flink;
304 ImageBase = Entry->DllBase;
305
306 /* Check if this is the right one */
307 if (((ULONG_PTR)Eip >= (ULONG_PTR)Entry->DllBase) &&
308 ((ULONG_PTR)Eip < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
309 {
310 /* Return this entry */
311 *LdrEntry = Entry;
312 EipBase = ImageBase;
313
314 /* Check if this was a kernel or HAL entry */
315 if (i <= 2) *InKernel = TRUE;
316 break;
317 }
318 }
319 }
320
321 /* Return the base address */
322 return EipBase;
323 #else
324 return 0;
325 #endif
326 }
327
328 PCHAR
329 NTAPI
330 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode,
331 OUT PCHAR Ansi,
332 IN ULONG Length)
333 {
334 PCHAR p;
335 PWCHAR pw;
336 ULONG i;
337
338 /* Set length and normalize it */
339 i = Unicode->Length / sizeof(WCHAR);
340 i = min(i, Length - 1);
341
342 /* Set source and destination, and copy */
343 pw = Unicode->Buffer;
344 p = Ansi;
345 while (i--) *p++ = (CHAR)*pw++;
346
347 /* Null terminate and return */
348 *p = ANSI_NULL;
349 return Ansi;
350 }
351
352 VOID
353 NTAPI
354 KiDumpParameterImages(IN PCHAR Message,
355 IN PULONG_PTR Parameters,
356 IN ULONG ParameterCount,
357 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine)
358 {
359 ULONG i;
360 BOOLEAN InSystem;
361 PLDR_DATA_TABLE_ENTRY LdrEntry;
362 PVOID ImageBase;
363 PUNICODE_STRING DriverName;
364 CHAR AnsiName[32];
365 PIMAGE_NT_HEADERS NtHeader;
366 ULONG TimeStamp;
367 BOOLEAN FirstRun = TRUE;
368
369 /* Loop parameters */
370 for (i = 0; i < ParameterCount; i++)
371 {
372 /* Get the base for this parameter */
373 ImageBase = KiPcToFileHeader((PVOID)Parameters[i],
374 &LdrEntry,
375 FALSE,
376 &InSystem);
377 if (!ImageBase)
378 {
379 /* Driver wasn't found, check for unloaded driver */
380 DriverName = NULL; // FIXME: ROS can't
381 if (!DriverName) continue;
382
383 /* Convert the driver name */
384 ImageBase = (PVOID)Parameters[i];
385 ConversionRoutine(DriverName, AnsiName, sizeof(AnsiName));
386 }
387 else
388 {
389 /* Get the NT Headers and Timestamp */
390 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
391 TimeStamp = NtHeader->FileHeader.TimeDateStamp;
392
393 /* Convert the driver name */
394 DriverName = &LdrEntry->BaseDllName;
395 ConversionRoutine(&LdrEntry->BaseDllName,
396 AnsiName,
397 sizeof(AnsiName));
398 }
399
400 /* Format driver name */
401 sprintf(Message,
402 "%s** %12s - Address %p base at %p, DateStamp %08lx\n",
403 FirstRun ? "\r\n*":"*",
404 AnsiName,
405 (PVOID)Parameters[i],
406 ImageBase,
407 TimeStamp);
408
409 /* Check if we only had one parameter */
410 if (ParameterCount <= 1)
411 {
412 /* Then just save the name */
413 KiBugCheckDriver = DriverName;
414 }
415 else
416 {
417 /* Otherwise, display the message */
418 InbvDisplayString(Message);
419 }
420
421 /* Loop again */
422 FirstRun = FALSE;
423 }
424 }
425
426 VOID
427 NTAPI
428 KiDisplayBlueScreen(IN ULONG MessageId,
429 IN BOOLEAN IsHardError,
430 IN PCHAR HardErrCaption OPTIONAL,
431 IN PCHAR HardErrMessage OPTIONAL,
432 IN PCHAR Message)
433 {
434 CHAR AnsiName[75];
435
436 /* FIXMEs: Use inbv to clear, fill and write to screen. */
437
438 /* Check if this is a hard error */
439 if (IsHardError)
440 {
441 /* Display caption and message */
442 if (HardErrCaption) InbvDisplayString(HardErrCaption);
443 if (HardErrMessage) InbvDisplayString(HardErrMessage);
444 return;
445 }
446
447 /* Begin the display */
448 InbvDisplayString("\r\n");
449
450 /* Print out initial message */
451 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL);
452 InbvDisplayString("\r\n\r\n");
453
454 /* Check if we have a driver */
455 if (KiBugCheckDriver)
456 {
457 /* Print out into to driver name */
458 KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
459
460 /* Convert and print out driver name */
461 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
462 InbvDisplayString(" ");
463 InbvDisplayString(AnsiName);
464 InbvDisplayString("\r\n\r\n");
465 }
466
467 /* Check if this is the generic message */
468 if (MessageId == BUGCODE_PSS_MESSAGE)
469 {
470 /* It is, so get the bug code string as well */
471 KeGetBugMessageText(KiBugCheckData[0], NULL);
472 InbvDisplayString("\r\n\r\n");
473 }
474
475 /* Print second introduction message */
476 KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL);
477 InbvDisplayString("\r\n\r\n");
478
479 /* Get the bug code string */
480 KeGetBugMessageText(MessageId, NULL);
481 InbvDisplayString("\r\n\r\n");
482
483 /* Print message for technical information */
484 KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
485
486 /* Show the techincal Data */
487 sprintf(AnsiName,
488 "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
489 KiBugCheckData[0],
490 (PVOID)KiBugCheckData[1],
491 (PVOID)KiBugCheckData[2],
492 (PVOID)KiBugCheckData[3],
493 (PVOID)KiBugCheckData[4]);
494 InbvDisplayString(AnsiName);
495
496 /* Check if we have a driver*/
497 if (KiBugCheckDriver)
498 {
499 /* Display technical driver data */
500 InbvDisplayString(Message);
501 }
502 else
503 {
504 /* Dump parameter information */
505 KiDumpParameterImages(Message,
506 (PVOID)&KiBugCheckData[1],
507 4,
508 KeBugCheckUnicodeToAnsi);
509 }
510 }
511
512 VOID
513 NTAPI
514 KeBugCheckWithTf(IN ULONG BugCheckCode,
515 IN ULONG_PTR BugCheckParameter1,
516 IN ULONG_PTR BugCheckParameter2,
517 IN ULONG_PTR BugCheckParameter3,
518 IN ULONG_PTR BugCheckParameter4,
519 IN PKTRAP_FRAME TrapFrame)
520 {
521 PKPRCB Prcb = KeGetCurrentPrcb();
522 CONTEXT Context;
523 ULONG MessageId;
524 CHAR AnsiName[128];
525 BOOLEAN IsSystem, IsHardError = FALSE;
526 PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
527 PVOID Eip = NULL, Memory;
528 PVOID DriverBase;
529 PLDR_DATA_TABLE_ENTRY LdrEntry;
530 PULONG_PTR HardErrorParameters;
531 KIRQL OldIrql;
532
533 /* Set active bugcheck */
534 KeBugCheckActive = TRUE;
535 KiBugCheckDriver = NULL;
536
537 /* Check if this is power failure simulation */
538 if (BugCheckCode == POWER_FAILURE_SIMULATE)
539 {
540 /* Call the Callbacks and reboot */;
541 KiDoBugCheckCallbacks();
542 HalReturnToFirmware(HalRebootRoutine);
543 }
544
545 /* Save the IRQL and set hardware trigger */
546 Prcb->DebuggerSavedIRQL = KeGetCurrentIrql();
547 InterlockedIncrement((PLONG)&KiHardwareTrigger);
548
549 /* Capture the CPU Context */
550 RtlCaptureContext((PVOID)&Prcb->ProcessorState.ContextFrame);
551 Context = Prcb->ProcessorState.ContextFrame;
552
553 /* FIXME: Call the Watchdog if it's regsitered */
554
555 /* Check which bugcode this is */
556 switch (BugCheckCode)
557 {
558 /* These bug checks already have detailed messages, keep them */
559 case UNEXPECTED_KERNEL_MODE_TRAP:
560 case DRIVER_CORRUPTED_EXPOOL:
561 case ACPI_BIOS_ERROR:
562 case ACPI_BIOS_FATAL_ERROR:
563 case THREAD_STUCK_IN_DEVICE_DRIVER:
564 case DATA_BUS_ERROR:
565 case FAT_FILE_SYSTEM:
566 case NO_MORE_SYSTEM_PTES:
567 case INACCESSIBLE_BOOT_DEVICE:
568 case KMODE_EXCEPTION_NOT_HANDLED:
569
570 /* Keep the same code */
571 MessageId = BugCheckCode;
572 break;
573
574 /* Check if this is a kernel-mode exception */
575 case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
576
577 /* Use the generic text message */
578 MessageId = KMODE_EXCEPTION_NOT_HANDLED;
579
580 /* File-system errors */
581 case NTFS_FILE_SYSTEM:
582
583 /* Use the generic message for FAT */
584 MessageId = FAT_FILE_SYSTEM;
585
586 /* Check if this is a coruption of the Mm's Pool */
587 case DRIVER_CORRUPTED_MMPOOL:
588
589 /* Use generic corruption message */
590 MessageId = DRIVER_CORRUPTED_EXPOOL;
591
592 /* Check if this is a signature check failure */
593 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
594
595 /* Use the generic corruption message */
596 MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE;
597
598 /* All other codes */
599 default:
600
601 /* Use the default bugcheck message */
602 MessageId = BUGCODE_PSS_MESSAGE;
603 }
604
605 /* Save bugcheck data */
606 KiBugCheckData[0] = BugCheckCode;
607 KiBugCheckData[1] = BugCheckParameter1;
608 KiBugCheckData[2] = BugCheckParameter2;
609 KiBugCheckData[3] = BugCheckParameter3;
610 KiBugCheckData[4] = BugCheckParameter4;
611
612 /* Now check what bugcheck this is */
613 switch (BugCheckCode)
614 {
615 /* Invalid access to R/O memory or Unhandled KM Exception */
616 case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
617 case ATTEMPTED_WRITE_TO_READONLY_MEMORY:
618 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY:
619
620 /* Check if we have a trap frame */
621 if (!TrapFrame)
622 {
623 /* Use parameter 3 as a trap frame, if it exists */
624 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
625 }
626
627 /* Check if we got one now and if we need to get EIP */
628 if ((TrapFrame) &&
629 (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
630 {
631 #ifdef _M_IX86
632 /* Get EIP */
633 Eip = (PVOID)TrapFrame->Eip;
634 #elif defined(_M_PPC)
635 Eip = (PVOID)TrapFrame->Iar;
636 #endif
637 }
638 break;
639
640 /* Wrong IRQL */
641 case IRQL_NOT_LESS_OR_EQUAL:
642
643 /*
644 * The NT kernel has 3 special sections:
645 * MISYSPTE, POOLMI and POOLCODE. The bug check code can
646 * determine in which of these sections this bugcode happened
647 * and provide a more detailed analysis. For now, we don't.
648 */
649
650 /* Eip is in parameter 4 */
651 Eip = (PVOID)BugCheckParameter4;
652
653 /* Get the driver base */
654 DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
655 if (IsSystem)
656 {
657 /*
658 * The error happened inside the kernel or HAL.
659 * Get the memory address that was being referenced.
660 */
661 Memory = (PVOID)BugCheckParameter1;
662
663 /* Find to which driver it belongs */
664 DriverBase = KiPcToFileHeader(Memory,
665 &LdrEntry,
666 TRUE,
667 &IsSystem);
668 if (DriverBase)
669 {
670 /* Get the driver name and update the bug code */
671 KiBugCheckDriver = &LdrEntry->BaseDllName;
672 KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED;
673 }
674 else
675 {
676 /* Find the driver that unloaded at this address */
677 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
678
679 /* Check if the cause was an unloaded driver */
680 if (KiBugCheckDriver)
681 {
682 /* Update bug check code */
683 KiBugCheckData[0] =
684 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD;
685 }
686 }
687 }
688 else
689 {
690 /* Update the bug check code */
691 KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
692 }
693
694 /* Clear EIP so we don't look it up later */
695 Eip = NULL;
696 break;
697
698 /* Hard error */
699 case FATAL_UNHANDLED_HARD_ERROR:
700
701 /* Copy bug check data from hard error */
702 HardErrorParameters = (PULONG_PTR)BugCheckParameter2;
703 KiBugCheckData[0] = BugCheckParameter1;
704 KiBugCheckData[1] = HardErrorParameters[0];
705 KiBugCheckData[2] = HardErrorParameters[1];
706 KiBugCheckData[3] = HardErrorParameters[2];
707 KiBugCheckData[4] = HardErrorParameters[3];
708
709 /* Remember that this is hard error and set the caption/message */
710 IsHardError = TRUE;
711 HardErrCaption = (PCHAR)BugCheckParameter3;
712 HardErrMessage = (PCHAR)BugCheckParameter4;
713 break;
714
715 /* Page fault */
716 case PAGE_FAULT_IN_NONPAGED_AREA:
717
718 /* Assume no driver */
719 DriverBase = NULL;
720
721 /* Check if we have a trap frame */
722 if (!TrapFrame)
723 {
724 /* We don't, use parameter 3 if possible */
725 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
726 }
727
728 /* Check if we have a frame now */
729 if (TrapFrame)
730 {
731 #ifdef _M_IX86
732 /* Get EIP */
733 Eip = (PVOID)TrapFrame->Eip;
734 #elif defined(_M_PPC)
735 Eip = (PVOID)TrapFrame->Iar;
736 #endif
737
738 /* Find out if was in the kernel or drivers */
739 DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
740 }
741
742 /*
743 * Now we should check if this happened in:
744 * 1) Special Pool 2) Free Special Pool 3) Session Pool
745 * and update the bugcheck code appropriately.
746 */
747
748 /* Check if we had a driver base */
749 if (DriverBase)
750 {
751 /* Find the driver that unloaded at this address */
752 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
753
754 /* Check if the cause was an unloaded driver */
755 if (KiBugCheckDriver)
756 {
757 KiBugCheckData[0] =
758 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS;
759 }
760 }
761 break;
762
763 /* Check if the driver forgot to unlock pages */
764 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
765
766 /* EIP is in parameter 1 */
767 Eip = (PVOID)BugCheckParameter1;
768 break;
769
770 /* Check if the driver consumed too many PTEs */
771 case DRIVER_USED_EXCESSIVE_PTES:
772
773 /* Driver base is in parameter 1 */
774 DriverBase = (PVOID)BugCheckParameter1;
775 /* FIXME: LdrEntry is uninitialized for god's sake!!!
776 KiBugCheckDriver = &LdrEntry->BaseDllName; */
777 break;
778
779 /* Check if the driver has a stuck thread */
780 case THREAD_STUCK_IN_DEVICE_DRIVER:
781
782 /* The name is in Parameter 3 */
783 KiBugCheckDriver = (PVOID)BugCheckParameter3;
784 break;
785
786 /* Anything else */
787 default:
788 break;
789 }
790
791 /* Do we have a driver name? */
792 if (KiBugCheckDriver)
793 {
794 /* Convert it to ANSI */
795 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
796 }
797 else
798 {
799 /* Do we have an EIP? */
800 if (Eip)
801 {
802 /* Dump image name */
803 KiDumpParameterImages(AnsiName,
804 (PULONG_PTR)&Eip,
805 1,
806 KeBugCheckUnicodeToAnsi);
807 }
808 }
809
810 /* FIXME: Check if we need to save the context for KD */
811
812 /* Check if a debugger is connected */
813 if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
814 {
815 /* Crash on the debugger console */
816 DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
817 " (0x%p,0x%p,0x%p,0x%p)\n\n",
818 KiBugCheckData[0],
819 KiBugCheckData[1],
820 KiBugCheckData[2],
821 KiBugCheckData[3],
822 KiBugCheckData[4]);
823
824 /* Check if the debugger isn't currently connected */
825 if (!KdDebuggerNotPresent)
826 {
827 /* Check if we have a driver to blame */
828 if (KiBugCheckDriver)
829 {
830 /* Dump it */
831 DbgPrint("Driver at fault: %s.\n", AnsiName);
832 }
833
834 /* Check if this was a hard error */
835 if (IsHardError)
836 {
837 /* Print caption and message */
838 if (HardErrCaption) DbgPrint(HardErrCaption);
839 if (HardErrMessage) DbgPrint(HardErrMessage);
840 }
841
842 /* Break in the debugger */
843 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST);
844 }
845 else
846 {
847 /*
848 * ROS HACK.
849 * Ok, so debugging is enabled, but KDBG isn't there.
850 * We'll manually dump the stack for the user.
851 */
852 KeRosDumpStackFrames(NULL, 0);
853 }
854 }
855
856 /* Switching back to the blue screen so we print messages on it */
857 HalReleaseDisplayOwnership();
858
859 /* Raise IRQL to HIGH_LEVEL */
860 KeDisableInterrupts();
861 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
862
863 /* Unlock the Kernel Adress Space if we own it */
864 if (KernelAddressSpaceLock.Owner == KeGetCurrentThread())
865 {
866 MmUnlockAddressSpace(MmGetKernelAddressSpace());
867 }
868
869 /* Avoid recursion */
870 if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
871 {
872 /* Set CPU that is bug checking now */
873 KeBugCheckOwner = Prcb->Number;
874
875 #ifdef CONFIG_SMP
876 /* Freeze the other CPUs */
877 for (i = 0; i < KeNumberProcessors; i++)
878 {
879 if (i != (LONG)KeGetCurrentProcessorNumber())
880 {
881 /* Send the IPI and give them one second to catch up */
882 KiIpiSendRequest(1 << i, IPI_FREEZE);
883 KeStallExecutionProcessor(1000000);
884 }
885 }
886 #endif
887
888 /* Display the BSOD */
889 KiDisplayBlueScreen(MessageId,
890 IsHardError,
891 HardErrCaption,
892 HardErrMessage,
893 AnsiName);
894
895 /* FIXME: Enable debugger if it was pending */
896
897 /* Print the last line */
898 InbvDisplayString("\r\n");
899
900 /* Save the context */
901 Prcb->ProcessorState.ContextFrame = Context;
902
903 /* FIXME: Support Triage Dump */
904
905 /* Write the crash dump */
906 MmDumpToPagingFile(KiBugCheckData[4],
907 KiBugCheckData[0],
908 KiBugCheckData[1],
909 KiBugCheckData[2],
910 KiBugCheckData[3],
911 TrapFrame);
912 }
913
914 /* Increase recursioun count */
915 KeBugCheckOwnerRecursionCount++;
916 if (KeBugCheckOwnerRecursionCount == 2)
917 {
918 /* Break in the debugger */
919 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
920 }
921 else if (KeBugCheckOwnerRecursionCount > 2)
922 {
923 /* Halt the CPU */
924 for (;;) KeHaltProcessor();
925 }
926
927 /* Call the Callbacks */
928 KiDoBugCheckCallbacks();
929
930 /* FIXME: Call Watchdog if enabled */
931
932 /* Attempt to break in the debugger (otherwise halt CPU) */
933 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
934 }
935
936 /* PUBLIC FUNCTIONS **********************************************************/
937
938 /*
939 * @implemented
940 */
941 BOOLEAN
942 NTAPI
943 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)
944 {
945 KIRQL OldIrql;
946 BOOLEAN Status = FALSE;
947
948 /* Raise IRQL to High */
949 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
950
951 /* Check the Current State */
952 if (CallbackRecord->State == BufferInserted)
953 {
954 /* Reset state and remove from list */
955 CallbackRecord->State = BufferEmpty;
956 RemoveEntryList(&CallbackRecord->Entry);
957 Status = TRUE;
958 }
959
960 /* Lower IRQL and return */
961 KeLowerIrql(OldIrql);
962 return Status;
963 }
964
965 /*
966 * @implemented
967 */
968 BOOLEAN
969 NTAPI
970 KeDeregisterBugCheckReasonCallback(
971 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)
972 {
973 KIRQL OldIrql;
974 BOOLEAN Status = FALSE;
975
976 /* Raise IRQL to High */
977 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
978
979 /* Check the Current State */
980 if (CallbackRecord->State == BufferInserted)
981 {
982 /* Reset state and remove from list */
983 CallbackRecord->State = BufferEmpty;
984 RemoveEntryList(&CallbackRecord->Entry);
985 Status = TRUE;
986 }
987
988 /* Lower IRQL and return */
989 KeLowerIrql(OldIrql);
990 return Status;
991 }
992
993 /*
994 * @implemented
995 */
996 BOOLEAN
997 NTAPI
998 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
999 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
1000 IN PVOID Buffer,
1001 IN ULONG Length,
1002 IN PUCHAR Component)
1003 {
1004 KIRQL OldIrql;
1005 BOOLEAN Status = FALSE;
1006
1007 /* Raise IRQL to High */
1008 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1009
1010 /* Check the Current State first so we don't double-register */
1011 if (CallbackRecord->State == BufferEmpty)
1012 {
1013 /* Set the Callback Settings and insert into the list */
1014 CallbackRecord->Length = Length;
1015 CallbackRecord->Buffer = Buffer;
1016 CallbackRecord->Component = Component;
1017 CallbackRecord->CallbackRoutine = CallbackRoutine;
1018 CallbackRecord->State = BufferInserted;
1019 InsertTailList(&BugcheckCallbackListHead, &CallbackRecord->Entry);
1020 Status = TRUE;
1021 }
1022
1023 /* Lower IRQL and return */
1024 KeLowerIrql(OldIrql);
1025 return Status;
1026 }
1027
1028 /*
1029 * @implemented
1030 */
1031 BOOLEAN
1032 NTAPI
1033 KeRegisterBugCheckReasonCallback(
1034 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
1035 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
1036 IN KBUGCHECK_CALLBACK_REASON Reason,
1037 IN PUCHAR Component)
1038 {
1039 KIRQL OldIrql;
1040 BOOLEAN Status = FALSE;
1041
1042 /* Raise IRQL to High */
1043 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1044
1045 /* Check the Current State first so we don't double-register */
1046 if (CallbackRecord->State == BufferEmpty)
1047 {
1048 /* Set the Callback Settings and insert into the list */
1049 CallbackRecord->Component = Component;
1050 CallbackRecord->CallbackRoutine = CallbackRoutine;
1051 CallbackRecord->State = BufferInserted;
1052 CallbackRecord->Reason = Reason;
1053 InsertTailList(&BugcheckReasonCallbackListHead,
1054 &CallbackRecord->Entry);
1055 Status = TRUE;
1056 }
1057
1058 /* Lower IRQL and return */
1059 KeLowerIrql(OldIrql);
1060 return Status;
1061 }
1062
1063 /*
1064 * @implemented
1065 */
1066 VOID
1067 NTAPI
1068 KeBugCheckEx(IN ULONG BugCheckCode,
1069 IN ULONG_PTR BugCheckParameter1,
1070 IN ULONG_PTR BugCheckParameter2,
1071 IN ULONG_PTR BugCheckParameter3,
1072 IN ULONG_PTR BugCheckParameter4)
1073 {
1074 /* Call the internal API */
1075 KeBugCheckWithTf(BugCheckCode,
1076 BugCheckParameter1,
1077 BugCheckParameter2,
1078 BugCheckParameter3,
1079 BugCheckParameter4,
1080 NULL);
1081 }
1082
1083 /*
1084 * @implemented
1085 */
1086 VOID
1087 NTAPI
1088 KeBugCheck(ULONG BugCheckCode)
1089 {
1090 /* Call the internal API */
1091 KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL);
1092 }
1093
1094 /* EOF */