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