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