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