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