NtGdiGetObject
[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 BugcheckCallbackListHead;
22 LIST_ENTRY BugcheckReasonCallbackListHead;
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 (!KeRosPrintAddress((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 = &BugcheckCallbackListHead;
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 this is a hard error */
431 if (IsHardError)
432 {
433 /* Display caption and message */
434 if (HardErrCaption) InbvDisplayString(HardErrCaption);
435 if (HardErrMessage) InbvDisplayString(HardErrMessage);
436 return;
437 }
438
439 /* Begin the display */
440 InbvDisplayString("\r\n");
441
442 /* Print out initial message */
443 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL);
444 InbvDisplayString("\r\n\r\n");
445
446 /* Check if we have a driver */
447 if (KiBugCheckDriver)
448 {
449 /* Print out into to driver name */
450 KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
451
452 /* Convert and print out driver name */
453 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
454 InbvDisplayString(" ");
455 InbvDisplayString(AnsiName);
456 InbvDisplayString("\r\n\r\n");
457 }
458
459 /* Check if this is the generic message */
460 if (MessageId == BUGCODE_PSS_MESSAGE)
461 {
462 /* It is, so get the bug code string as well */
463 KeGetBugMessageText(KiBugCheckData[0], NULL);
464 InbvDisplayString("\r\n\r\n");
465 }
466
467 /* Print second introduction message */
468 KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL);
469 InbvDisplayString("\r\n\r\n");
470
471 /* Get the bug code string */
472 KeGetBugMessageText(MessageId, NULL);
473 InbvDisplayString("\r\n\r\n");
474
475 /* Print message for technical information */
476 KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
477
478 /* Show the techincal Data */
479 sprintf(AnsiName,
480 "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
481 KiBugCheckData[0],
482 (PVOID)KiBugCheckData[1],
483 (PVOID)KiBugCheckData[2],
484 (PVOID)KiBugCheckData[3],
485 (PVOID)KiBugCheckData[4]);
486 InbvDisplayString(AnsiName);
487
488 /* Check if we have a driver*/
489 if (KiBugCheckDriver)
490 {
491 /* Display technical driver data */
492 InbvDisplayString(Message);
493 }
494 else
495 {
496 /* Dump parameter information */
497 KiDumpParameterImages(Message,
498 (PVOID)&KiBugCheckData[1],
499 4,
500 KeBugCheckUnicodeToAnsi);
501 }
502 }
503
504 VOID
505 NTAPI
506 KeBugCheckWithTf(IN ULONG BugCheckCode,
507 IN ULONG_PTR BugCheckParameter1,
508 IN ULONG_PTR BugCheckParameter2,
509 IN ULONG_PTR BugCheckParameter3,
510 IN ULONG_PTR BugCheckParameter4,
511 IN PKTRAP_FRAME TrapFrame)
512 {
513 PKPRCB Prcb = KeGetCurrentPrcb();
514 CONTEXT Context;
515 ULONG MessageId;
516 CHAR AnsiName[128];
517 BOOLEAN IsSystem, IsHardError = FALSE;
518 PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
519 PVOID Eip = NULL, Memory;
520 PVOID DriverBase;
521 PLDR_DATA_TABLE_ENTRY LdrEntry;
522 PULONG_PTR HardErrorParameters;
523 KIRQL OldIrql;
524 #ifdef CONFIG_SMP
525 LONG i = 0;
526 #endif
527
528 /* Set active bugcheck */
529 KeBugCheckActive = TRUE;
530 KiBugCheckDriver = NULL;
531
532 /* Check if this is power failure simulation */
533 if (BugCheckCode == POWER_FAILURE_SIMULATE)
534 {
535 /* Call the Callbacks and reboot */;
536 KiDoBugCheckCallbacks();
537 HalReturnToFirmware(HalRebootRoutine);
538 }
539
540 /* Save the IRQL and set hardware trigger */
541 Prcb->DebuggerSavedIRQL = KeGetCurrentIrql();
542 InterlockedIncrement((PLONG)&KiHardwareTrigger);
543
544 /* Capture the CPU Context */
545 RtlCaptureContext(&Prcb->ProcessorState.ContextFrame);
546 Context = Prcb->ProcessorState.ContextFrame;
547
548 /* FIXME: Call the Watchdog if it's regsitered */
549
550 /* Check which bugcode this is */
551 switch (BugCheckCode)
552 {
553 /* These bug checks already have detailed messages, keep them */
554 case UNEXPECTED_KERNEL_MODE_TRAP:
555 case DRIVER_CORRUPTED_EXPOOL:
556 case ACPI_BIOS_ERROR:
557 case ACPI_BIOS_FATAL_ERROR:
558 case THREAD_STUCK_IN_DEVICE_DRIVER:
559 case DATA_BUS_ERROR:
560 case FAT_FILE_SYSTEM:
561 case NO_MORE_SYSTEM_PTES:
562 case INACCESSIBLE_BOOT_DEVICE:
563 case KMODE_EXCEPTION_NOT_HANDLED:
564
565 /* Keep the same code */
566 MessageId = BugCheckCode;
567 break;
568
569 /* Check if this is a kernel-mode exception */
570 case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
571
572 /* Use the generic text message */
573 MessageId = KMODE_EXCEPTION_NOT_HANDLED;
574
575 /* File-system errors */
576 case NTFS_FILE_SYSTEM:
577
578 /* Use the generic message for FAT */
579 MessageId = FAT_FILE_SYSTEM;
580
581 /* Check if this is a coruption of the Mm's Pool */
582 case DRIVER_CORRUPTED_MMPOOL:
583
584 /* Use generic corruption message */
585 MessageId = DRIVER_CORRUPTED_EXPOOL;
586
587 /* Check if this is a signature check failure */
588 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
589
590 /* Use the generic corruption message */
591 MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE;
592
593 /* All other codes */
594 default:
595
596 /* Use the default bugcheck message */
597 MessageId = BUGCODE_PSS_MESSAGE;
598 }
599
600 /* Save bugcheck data */
601 KiBugCheckData[0] = BugCheckCode;
602 KiBugCheckData[1] = BugCheckParameter1;
603 KiBugCheckData[2] = BugCheckParameter2;
604 KiBugCheckData[3] = BugCheckParameter3;
605 KiBugCheckData[4] = BugCheckParameter4;
606
607 /* Now check what bugcheck this is */
608 switch (BugCheckCode)
609 {
610 /* Invalid access to R/O memory or Unhandled KM Exception */
611 case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
612 case ATTEMPTED_WRITE_TO_READONLY_MEMORY:
613 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY:
614
615 /* Check if we have a trap frame */
616 if (!TrapFrame)
617 {
618 /* Use parameter 3 as a trap frame, if it exists */
619 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
620 }
621
622 /* Check if we got one now and if we need to get EIP */
623 if ((TrapFrame) &&
624 (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
625 {
626 /* Get EIP */
627 Eip = (PVOID)TrapFrame->Eip;
628 }
629 break;
630
631 /* Wrong IRQL */
632 case IRQL_NOT_LESS_OR_EQUAL:
633
634 /*
635 * The NT kernel has 3 special sections:
636 * MISYSPTE, POOLMI and POOLCODE. The bug check code can
637 * determine in which of these sections this bugcode happened
638 * and provide a more detailed analysis. For now, we don't.
639 */
640
641 /* Eip is in parameter 4 */
642 Eip = (PVOID)BugCheckParameter4;
643
644 /* Get the driver base */
645 DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
646 if (IsSystem)
647 {
648 /*
649 * The error happened inside the kernel or HAL.
650 * Get the memory address that was being referenced.
651 */
652 Memory = (PVOID)BugCheckParameter1;
653
654 /* Find to which driver it belongs */
655 DriverBase = KiPcToFileHeader(Memory,
656 &LdrEntry,
657 TRUE,
658 &IsSystem);
659 if (DriverBase)
660 {
661 /* Get the driver name and update the bug code */
662 KiBugCheckDriver = &LdrEntry->BaseDllName;
663 KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED;
664 }
665 else
666 {
667 /* Find the driver that unloaded at this address */
668 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
669
670 /* Check if the cause was an unloaded driver */
671 if (KiBugCheckDriver)
672 {
673 /* Update bug check code */
674 KiBugCheckData[0] =
675 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD;
676 }
677 }
678 }
679 else
680 {
681 /* Update the bug check code */
682 KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
683 }
684
685 /* Clear EIP so we don't look it up later */
686 Eip = NULL;
687 break;
688
689 /* Hard error */
690 case FATAL_UNHANDLED_HARD_ERROR:
691
692 /* Copy bug check data from hard error */
693 HardErrorParameters = (PULONG_PTR)BugCheckParameter2;
694 KiBugCheckData[0] = BugCheckParameter1;
695 KiBugCheckData[1] = HardErrorParameters[0];
696 KiBugCheckData[2] = HardErrorParameters[1];
697 KiBugCheckData[3] = HardErrorParameters[2];
698 KiBugCheckData[4] = HardErrorParameters[3];
699
700 /* Remember that this is hard error and set the caption/message */
701 IsHardError = TRUE;
702 HardErrCaption = (PCHAR)BugCheckParameter3;
703 HardErrMessage = (PCHAR)BugCheckParameter4;
704 break;
705
706 /* Page fault */
707 case PAGE_FAULT_IN_NONPAGED_AREA:
708
709 /* Assume no driver */
710 DriverBase = NULL;
711
712 /* Check if we have a trap frame */
713 if (!TrapFrame)
714 {
715 /* We don't, use parameter 3 if possible */
716 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
717 }
718
719 /* Check if we have a frame now */
720 if (TrapFrame)
721 {
722 /* Get EIP */
723 Eip = (PVOID)TrapFrame->Eip;
724
725 /* Find out if was in the kernel or drivers */
726 DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
727 }
728
729 /*
730 * Now we should check if this happened in:
731 * 1) Special Pool 2) Free Special Pool 3) Session Pool
732 * and update the bugcheck code appropriately.
733 */
734
735 /* Check if we had a driver base */
736 if (DriverBase)
737 {
738 /* Find the driver that unloaded at this address */
739 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
740
741 /* Check if the cause was an unloaded driver */
742 if (KiBugCheckDriver)
743 {
744 KiBugCheckData[0] =
745 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS;
746 }
747 }
748 break;
749
750 /* Check if the driver forgot to unlock pages */
751 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
752
753 /* EIP is in parameter 1 */
754 Eip = (PVOID)BugCheckParameter1;
755 break;
756
757 /* Check if the driver consumed too many PTEs */
758 case DRIVER_USED_EXCESSIVE_PTES:
759
760 /* Driver base is in parameter 1 */
761 DriverBase = (PVOID)BugCheckParameter1;
762 /* FIXME: LdrEntry is uninitialized for god's sake!!!
763 KiBugCheckDriver = &LdrEntry->BaseDllName; */
764 break;
765
766 /* Check if the driver has a stuck thread */
767 case THREAD_STUCK_IN_DEVICE_DRIVER:
768
769 /* The name is in Parameter 3 */
770 KiBugCheckDriver = (PVOID)BugCheckParameter3;
771 break;
772
773 /* Anything else */
774 default:
775 break;
776 }
777
778 /* Do we have a driver name? */
779 if (KiBugCheckDriver)
780 {
781 /* Convert it to ANSI */
782 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
783 }
784 else
785 {
786 /* Do we have an EIP? */
787 if (Eip)
788 {
789 /* Dump image name */
790 KiDumpParameterImages(AnsiName,
791 (PULONG_PTR)&Eip,
792 1,
793 KeBugCheckUnicodeToAnsi);
794 }
795 }
796
797 /* FIXME: Check if we need to save the context for KD */
798
799 /* Check if a debugger is connected */
800 if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
801 {
802 /* Crash on the debugger console */
803 DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
804 " (0x%p,0x%p,0x%p,0x%p)\n\n",
805 KiBugCheckData[0],
806 KiBugCheckData[1],
807 KiBugCheckData[2],
808 KiBugCheckData[3],
809 KiBugCheckData[4]);
810
811 /* Check if the debugger isn't currently connected */
812 if (!KdDebuggerNotPresent)
813 {
814 /* Check if we have a driver to blame */
815 if (KiBugCheckDriver)
816 {
817 /* Dump it */
818 DbgPrint("Driver at fault: %s.\n", AnsiName);
819 }
820
821 /* Check if this was a hard error */
822 if (IsHardError)
823 {
824 /* Print caption and message */
825 if (HardErrCaption) DbgPrint(HardErrCaption);
826 if (HardErrMessage) DbgPrint(HardErrMessage);
827 }
828
829 /* Break in the debugger */
830 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST);
831 }
832 else
833 {
834 /*
835 * ROS HACK.
836 * Ok, so debugging is enabled, but KDBG isn't there.
837 * We'll manually dump the stack for the user.
838 */
839 KeRosDumpStackFrames(NULL, 0);
840 }
841 }
842
843 /* Use the boot video driver to clear, fill and write to screen. */
844 if (InbvIsBootDriverInstalled())
845 {
846 /* FIXME: This should happen in KiDisplayBlueScreen!!! */
847 InbvAcquireDisplayOwnership();
848 InbvResetDisplay();
849 InbvSolidColorFill(0, 0, 639, 479, 4);
850 InbvSetTextColor(15);
851 InbvInstallDisplayStringFilter(NULL);
852 InbvEnableDisplayString(TRUE);
853 InbvSetScrollRegion(0, 0, 639, 479);
854 }
855
856 /* Raise IRQL to HIGH_LEVEL */
857 _disable();
858 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
859
860 /* Unlock the Kernel Adress Space if we own it */
861 if (KernelAddressSpaceLock.Owner == KeGetCurrentThread())
862 {
863 MmUnlockAddressSpace(MmGetKernelAddressSpace());
864 }
865
866 /* Avoid recursion */
867 if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
868 {
869 /* Set CPU that is bug checking now */
870 KeBugCheckOwner = Prcb->Number;
871
872 #ifdef CONFIG_SMP
873 /* Freeze the other CPUs */
874 for (i = 0; i < KeNumberProcessors; i++)
875 {
876 if (i != (LONG)KeGetCurrentProcessorNumber())
877 {
878 /* Send the IPI and give them one second to catch up */
879 KiIpiSendRequest(1 << i, IPI_FREEZE);
880 KeStallExecutionProcessor(1000000);
881 }
882 }
883 #endif
884
885 /* Display the BSOD */
886 KiDisplayBlueScreen(MessageId,
887 IsHardError,
888 HardErrCaption,
889 HardErrMessage,
890 AnsiName);
891
892 /* FIXME: Enable debugger if it was pending */
893
894 /* Print the last line */
895 InbvDisplayString("\r\n");
896
897 /* Save the context */
898 Prcb->ProcessorState.ContextFrame = Context;
899
900 /* FIXME: Support Triage Dump */
901
902 /* Write the crash dump */
903 MmDumpToPagingFile(KiBugCheckData[4],
904 KiBugCheckData[0],
905 KiBugCheckData[1],
906 KiBugCheckData[2],
907 KiBugCheckData[3],
908 TrapFrame);
909 }
910
911 /* Increase recursioun count */
912 KeBugCheckOwnerRecursionCount++;
913 if (KeBugCheckOwnerRecursionCount == 2)
914 {
915 /* Break in the debugger */
916 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
917 }
918 else if (KeBugCheckOwnerRecursionCount > 2)
919 {
920 /* Halt the CPU */
921 for (;;) Ke386HaltProcessor();
922 }
923
924 /* Call the Callbacks */
925 KiDoBugCheckCallbacks();
926
927 /* FIXME: Call Watchdog if enabled */
928
929 /* Attempt to break in the debugger (otherwise halt CPU) */
930 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
931 }
932
933 /* PUBLIC FUNCTIONS **********************************************************/
934
935 /*
936 * @implemented
937 */
938 BOOLEAN
939 NTAPI
940 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)
941 {
942 KIRQL OldIrql;
943 BOOLEAN Status = FALSE;
944
945 /* Raise IRQL to High */
946 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
947
948 /* Check the Current State */
949 if (CallbackRecord->State == BufferInserted)
950 {
951 /* Reset state and remove from list */
952 CallbackRecord->State = BufferEmpty;
953 RemoveEntryList(&CallbackRecord->Entry);
954 Status = TRUE;
955 }
956
957 /* Lower IRQL and return */
958 KeLowerIrql(OldIrql);
959 return Status;
960 }
961
962 /*
963 * @implemented
964 */
965 BOOLEAN
966 NTAPI
967 KeDeregisterBugCheckReasonCallback(
968 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)
969 {
970 KIRQL OldIrql;
971 BOOLEAN Status = FALSE;
972
973 /* Raise IRQL to High */
974 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
975
976 /* Check the Current State */
977 if (CallbackRecord->State == BufferInserted)
978 {
979 /* Reset state and remove from list */
980 CallbackRecord->State = BufferEmpty;
981 RemoveEntryList(&CallbackRecord->Entry);
982 Status = TRUE;
983 }
984
985 /* Lower IRQL and return */
986 KeLowerIrql(OldIrql);
987 return Status;
988 }
989
990 /*
991 * @implemented
992 */
993 BOOLEAN
994 NTAPI
995 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
996 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
997 IN PVOID Buffer,
998 IN ULONG Length,
999 IN PUCHAR Component)
1000 {
1001 KIRQL OldIrql;
1002 BOOLEAN Status = FALSE;
1003
1004 /* Raise IRQL to High */
1005 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1006
1007 /* Check the Current State first so we don't double-register */
1008 if (CallbackRecord->State == BufferEmpty)
1009 {
1010 /* Set the Callback Settings and insert into the list */
1011 CallbackRecord->Length = Length;
1012 CallbackRecord->Buffer = Buffer;
1013 CallbackRecord->Component = Component;
1014 CallbackRecord->CallbackRoutine = CallbackRoutine;
1015 CallbackRecord->State = BufferInserted;
1016 InsertTailList(&BugcheckCallbackListHead, &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 KeRegisterBugCheckReasonCallback(
1031 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
1032 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
1033 IN KBUGCHECK_CALLBACK_REASON Reason,
1034 IN PUCHAR Component)
1035 {
1036 KIRQL OldIrql;
1037 BOOLEAN Status = FALSE;
1038
1039 /* Raise IRQL to High */
1040 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1041
1042 /* Check the Current State first so we don't double-register */
1043 if (CallbackRecord->State == BufferEmpty)
1044 {
1045 /* Set the Callback Settings and insert into the list */
1046 CallbackRecord->Component = Component;
1047 CallbackRecord->CallbackRoutine = CallbackRoutine;
1048 CallbackRecord->State = BufferInserted;
1049 CallbackRecord->Reason = Reason;
1050 InsertTailList(&BugcheckReasonCallbackListHead,
1051 &CallbackRecord->Entry);
1052 Status = TRUE;
1053 }
1054
1055 /* Lower IRQL and return */
1056 KeLowerIrql(OldIrql);
1057 return Status;
1058 }
1059
1060 /*
1061 * @implemented
1062 */
1063 VOID
1064 NTAPI
1065 KeBugCheckEx(IN ULONG BugCheckCode,
1066 IN ULONG_PTR BugCheckParameter1,
1067 IN ULONG_PTR BugCheckParameter2,
1068 IN ULONG_PTR BugCheckParameter3,
1069 IN ULONG_PTR BugCheckParameter4)
1070 {
1071 /* Call the internal API */
1072 KeBugCheckWithTf(BugCheckCode,
1073 BugCheckParameter1,
1074 BugCheckParameter2,
1075 BugCheckParameter3,
1076 BugCheckParameter4,
1077 NULL);
1078 }
1079
1080 /*
1081 * @implemented
1082 */
1083 VOID
1084 NTAPI
1085 KeBugCheck(ULONG BugCheckCode)
1086 {
1087 /* Call the internal API */
1088 KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL);
1089 }
1090
1091 /* EOF */