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