ab094e2aefc287f62141d2406275e19c0cc54f87
[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 <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 /* Bugzilla Reporting */
33 UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion;
34 UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion;
35
36 /* PRIVATE FUNCTIONS *********************************************************/
37
38 PVOID
39 NTAPI
40 KiPcToFileHeader(IN PVOID Eip,
41 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry,
42 IN BOOLEAN DriversOnly,
43 OUT PBOOLEAN InKernel)
44 {
45 ULONG i = 0;
46 PVOID ImageBase, EipBase = NULL;
47 PLDR_DATA_TABLE_ENTRY Entry;
48 PLIST_ENTRY ListHead, NextEntry;
49
50 /* Check which list we should use */
51 ListHead = (KeLoaderBlock) ? &KeLoaderBlock->LoadOrderListHead :
52 &PsLoadedModuleList;
53
54 /* Assume no */
55 *InKernel = FALSE;
56
57 /* Set list pointers and make sure it's valid */
58 NextEntry = ListHead->Flink;
59 if (NextEntry)
60 {
61 /* Start loop */
62 while (NextEntry != ListHead)
63 {
64 /* Increase entry */
65 i++;
66
67 /* Check if this is a kernel entry and we only want drivers */
68 if ((i <= 2) && (DriversOnly == TRUE))
69 {
70 /* Skip it */
71 NextEntry = NextEntry->Flink;
72 continue;
73 }
74
75 /* Get the loader entry */
76 Entry = CONTAINING_RECORD(NextEntry,
77 LDR_DATA_TABLE_ENTRY,
78 InLoadOrderLinks);
79
80 /* Move to the next entry */
81 NextEntry = NextEntry->Flink;
82 ImageBase = Entry->DllBase;
83
84 /* Check if this is the right one */
85 if (((ULONG_PTR)Eip >= (ULONG_PTR)Entry->DllBase) &&
86 ((ULONG_PTR)Eip < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
87 {
88 /* Return this entry */
89 *LdrEntry = Entry;
90 EipBase = ImageBase;
91
92 /* Check if this was a kernel or HAL entry */
93 if (i <= 2) *InKernel = TRUE;
94 break;
95 }
96 }
97 }
98
99 /* Return the base address */
100 return EipBase;
101 }
102
103 BOOLEAN
104 NTAPI
105 KiRosPrintAddress(PVOID address)
106 {
107 PLIST_ENTRY current_entry;
108 PLDR_DATA_TABLE_ENTRY current;
109 extern LIST_ENTRY PsLoadedModuleList;
110 ULONG_PTR RelativeAddress;
111 ULONG i = 0;
112
113 do
114 {
115 current_entry = PsLoadedModuleList.Flink;
116
117 while (current_entry != &PsLoadedModuleList)
118 {
119 current = CONTAINING_RECORD(current_entry,
120 LDR_DATA_TABLE_ENTRY,
121 InLoadOrderLinks);
122
123 if (address >= (PVOID)current->DllBase &&
124 address < (PVOID)((ULONG_PTR)current->DllBase +
125 current->SizeOfImage))
126 {
127 RelativeAddress = (ULONG_PTR)address -
128 (ULONG_PTR)current->DllBase;
129 DbgPrint("<%wZ: %x>", &current->FullDllName, RelativeAddress);
130 return(TRUE);
131 }
132 current_entry = current_entry->Flink;
133 }
134 } while(++i <= 1);
135
136 return(FALSE);
137 }
138
139 PVOID
140 NTAPI
141 KiRosPcToUserFileHeader(IN PVOID Eip,
142 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
143 {
144 PVOID ImageBase, EipBase = NULL;
145 PLDR_DATA_TABLE_ENTRY Entry;
146 PLIST_ENTRY ListHead, NextEntry;
147
148 /*
149 * We know this is valid because we should only be called after a
150 * succesfull address from RtlWalkFrameChain for UserMode, which
151 * validates everything for us.
152 */
153 ListHead = &KeGetCurrentThread()->
154 Teb->ProcessEnvironmentBlock->Ldr->InLoadOrderModuleList;
155
156 /* Set list pointers and make sure it's valid */
157 NextEntry = ListHead->Flink;
158 if (NextEntry)
159 {
160 /* Start loop */
161 while (NextEntry != ListHead)
162 {
163 /* Get the loader entry */
164 Entry = CONTAINING_RECORD(NextEntry,
165 LDR_DATA_TABLE_ENTRY,
166 InLoadOrderLinks);
167
168 /* Move to the next entry */
169 NextEntry = NextEntry->Flink;
170 ImageBase = Entry->DllBase;
171
172 /* Check if this is the right one */
173 if (((ULONG_PTR)Eip >= (ULONG_PTR)Entry->DllBase) &&
174 ((ULONG_PTR)Eip < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
175 {
176 /* Return this entry */
177 *LdrEntry = Entry;
178 EipBase = ImageBase;
179 break;
180 }
181 }
182 }
183
184 /* Return the base address */
185 return EipBase;
186 }
187
188 USHORT
189 NTAPI
190 KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip,
191 IN ULONG FramesToCapture,
192 OUT PVOID *BackTrace,
193 OUT PULONG BackTraceHash OPTIONAL)
194 {
195 PVOID Frames[2 * 64];
196 ULONG FrameCount;
197 ULONG Hash = 0, i;
198
199 /* Skip a frame for the caller */
200 FramesToSkip++;
201
202 /* Don't go past the limit */
203 if ((FramesToCapture + FramesToSkip) >= 128) return 0;
204
205 /* Do the back trace */
206 FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 1);
207
208 /* Make sure we're not skipping all of them */
209 if (FrameCount <= FramesToSkip) return 0;
210
211 /* Loop all the frames */
212 for (i = 0; i < FramesToCapture; i++)
213 {
214 /* Don't go past the limit */
215 if ((FramesToSkip + i) >= FrameCount) break;
216
217 /* Save this entry and hash it */
218 BackTrace[i] = Frames[FramesToSkip + i];
219 Hash += PtrToUlong(BackTrace[i]);
220 }
221
222 /* Write the hash */
223 if (BackTraceHash) *BackTraceHash = Hash;
224
225 /* Clear the other entries and return count */
226 RtlFillMemoryUlong(Frames, 128, 0);
227 return (USHORT)i;
228 }
229
230
231 VOID
232 FASTCALL
233 KeRosDumpStackFrameArray(IN PULONG Frames,
234 IN ULONG FrameCount)
235 {
236 ULONG i, Addr;
237 BOOLEAN InSystem;
238 PVOID p;
239
240 /* GCC complaints that it may be used uninitialized */
241 PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
242
243 /* Loop them */
244 for (i = 0; i < FrameCount; i++)
245 {
246 /* Get the EIP */
247 Addr = Frames[i];
248 if (!Addr)
249 {
250 break;
251 }
252
253 /* Get the base for this file */
254 if (Addr > (ULONG_PTR)MmHighestUserAddress)
255 {
256 /* We are in kernel */
257 p = KiPcToFileHeader((PVOID)Addr, &LdrEntry, FALSE, &InSystem);
258 }
259 else
260 {
261 /* We are in user land */
262 p = KiRosPcToUserFileHeader((PVOID)Addr, &LdrEntry);
263 }
264 if (p)
265 {
266 #ifdef KDBG
267 if (!KdbSymPrintAddress((PVOID)Addr))
268 #endif
269 {
270 /* Print out the module name */
271 Addr -= (ULONG_PTR)LdrEntry->DllBase;
272 DbgPrint("<%wZ: %x>\n", &LdrEntry->FullDllName, Addr);
273 }
274 }
275 else
276 {
277 /* Print only the address */
278 DbgPrint("<%x>\n", Addr);
279 }
280
281 /* Go to the next frame */
282 DbgPrint("\n");
283 }
284 }
285
286 VOID
287 NTAPI
288 KeRosDumpStackFrames(IN PULONG Frame OPTIONAL,
289 IN ULONG FrameCount OPTIONAL)
290 {
291 ULONG Frames[32];
292 ULONG RealFrameCount;
293
294 /* If the caller didn't ask, assume 32 frames */
295 if (!FrameCount || FrameCount > 32) FrameCount = 32;
296
297 if (Frame)
298 {
299 /* Dump them */
300 KeRosDumpStackFrameArray(Frame, FrameCount);
301 }
302 else
303 {
304 /* Get the current frames (skip the two. One for the dumper, one for the caller) */
305 RealFrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL);
306
307 /* Dump them */
308 KeRosDumpStackFrameArray(Frames, RealFrameCount);
309
310 /* Count left for user mode? */
311 if (FrameCount - RealFrameCount > 0)
312 {
313 /* Get the current frames */
314 RealFrameCount = KeRosCaptureUserStackBackTrace(-1, FrameCount - RealFrameCount, (PVOID*)Frames, NULL);
315
316 /* Dump them */
317 KeRosDumpStackFrameArray(Frames, RealFrameCount);
318 }
319 }
320 }
321
322 VOID
323 NTAPI
324 KeRosDumpTriageForBugZillaReport(VOID)
325 {
326 #if 0
327 extern BOOLEAN KiFastSystemCallDisable, KiSMTProcessorsPresent;
328 extern ULONG KeI386MachineType, MxcsrFeatureMask;
329 extern BOOLEAN Ke386Pae, Ke386NoExecute;
330
331 DbgPrint("ReactOS has crashed! Please go to http://www.reactos.org/bugzilla/enter_bug.cgi to file a bug!\n");
332 DbgPrint("\nHardware Information\n");
333 DbgPrint("Processor Architecture: %d\n"
334 "Feature Bits: %d\n"
335 "System Call Disabled: %d\n"
336 "NPX Present: %d\n"
337 "MXCsr Mask: %d\n"
338 "MXCsr Feature Mask: %d\n"
339 "XMMI Present: %d\n"
340 "FXSR Present: %d\n"
341 "Machine Type: %d\n"
342 "PAE: %d\n"
343 "NX: %d\n"
344 "Processors: %d\n"
345 "Active Processors: %d\n"
346 "Pentium LOCK Bug: %d\n"
347 "Hyperthreading: %d\n"
348 "CPU Manufacturer: %s\n"
349 "CPU Name: %wZ\n"
350 "CPUID: %d\n"
351 "CPU Type: %d\n"
352 "CPU Stepping: %d\n"
353 "CPU Speed: %d\n"
354 "CPU L2 Cache: %d\n"
355 "BIOS Date: %wZ\n"
356 "BIOS Version: %wZ\n"
357 "Video BIOS Date: %wZ\n"
358 "Video BIOS Version: %wZ\n"
359 "Memory: %d\n",
360 KeProcessorArchitecture,
361 KeFeatureBits,
362 KiFastSystemCallDisable,
363 KeI386NpxPresent,
364 KiMXCsrMask,
365 MxcsrFeatureMask,
366 KeI386XMMIPresent,
367 KeI386FxsrPresent,
368 KeI386MachineType,
369 Ke386Pae,
370 Ke386NoExecute,
371 KeNumberProcessors,
372 KeActiveProcessors,
373 KiI386PentiumLockErrataPresent,
374 KiSMTProcessorsPresent,
375 KeGetCurrentPrcb()->VendorString,
376 &KeRosProcessorName,
377 KeGetCurrentPrcb()->CpuID,
378 KeGetCurrentPrcb()->CpuType,
379 KeGetCurrentPrcb()->CpuStep,
380 KeGetCurrentPrcb()->MHz,
381 ((PKIPCR)KeGetPcr())->SecondLevelCacheSize,
382 &KeRosBiosDate,
383 &KeRosBiosVersion,
384 &KeRosVideoBiosDate,
385 &KeRosVideoBiosVersion,
386 MmNumberOfPhysicalPages * PAGE_SIZE);
387 #endif
388 }
389
390 VOID
391 INIT_FUNCTION
392 NTAPI
393 KiInitializeBugCheck(VOID)
394 {
395 PRTL_MESSAGE_RESOURCE_DATA BugCheckData;
396 LDR_RESOURCE_INFO ResourceInfo;
397 PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
398 NTSTATUS Status;
399 PLDR_DATA_TABLE_ENTRY LdrEntry;
400
401 /* Get the kernel entry */
402 LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink,
403 LDR_DATA_TABLE_ENTRY,
404 InLoadOrderLinks);
405
406 /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
407 ResourceInfo.Type = 11;
408 ResourceInfo.Name = 1;
409 ResourceInfo.Language = 9;
410
411 /* Do the lookup. */
412 Status = LdrFindResource_U(LdrEntry->DllBase,
413 &ResourceInfo,
414 RESOURCE_DATA_LEVEL,
415 &ResourceDataEntry);
416
417 /* Make sure it worked */
418 if (NT_SUCCESS(Status))
419 {
420 /* Now actually get a pointer to it */
421 Status = LdrAccessResource(LdrEntry->DllBase,
422 ResourceDataEntry,
423 (PVOID*)&BugCheckData,
424 NULL);
425 if (NT_SUCCESS(Status)) KiBugCodeMessages = BugCheckData;
426 }
427 }
428
429 BOOLEAN
430 NTAPI
431 KeGetBugMessageText(IN ULONG BugCheckCode,
432 OUT PANSI_STRING OutputString OPTIONAL)
433 {
434 ULONG i;
435 ULONG IdOffset;
436 ULONG_PTR MessageEntry;
437 PCHAR BugCode;
438 BOOLEAN Result = FALSE;
439
440 /* Make sure we're not bugchecking too early */
441 if (!KiBugCodeMessages) return Result;
442
443 /* Find the message. This code is based on RtlFindMesssage */
444 for (i = 0; i < KiBugCodeMessages->NumberOfBlocks; i++)
445 {
446 /* Check if the ID Matches */
447 if ((BugCheckCode >= KiBugCodeMessages->Blocks[i].LowId) &&
448 (BugCheckCode <= KiBugCodeMessages->Blocks[i].HighId))
449 {
450 /* Get Offset to Entry */
451 MessageEntry = KiBugCodeMessages->Blocks[i].OffsetToEntries +
452 (ULONG_PTR)KiBugCodeMessages;
453 IdOffset = BugCheckCode - KiBugCodeMessages->Blocks[i].LowId;
454
455 /* Get offset to ID */
456 for (i = 0; i < IdOffset; i++)
457 {
458 /* Advance in the Entries */
459 MessageEntry += ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->
460 Length;
461 }
462
463 /* Get the final Code */
464 BugCode = ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->Text;
465 i = strlen(BugCode);
466
467 /* Handle newlines */
468 while ((i > 0) && ((BugCode[i] == '\n') ||
469 (BugCode[i] == '\r') ||
470 (BugCode[i] == ANSI_NULL)))
471 {
472 /* Check if we have a string to return */
473 if (!OutputString) BugCode[i] = ANSI_NULL;
474 i--;
475 }
476
477 /* Check if caller wants an output string */
478 if (OutputString)
479 {
480 /* Return it in the OutputString */
481 OutputString->Buffer = BugCode;
482 OutputString->Length = (USHORT)i + 1;
483 OutputString->MaximumLength = (USHORT)i + 1;
484 }
485 else
486 {
487 /* Direct Output to Screen */
488 InbvDisplayString(BugCode);
489 InbvDisplayString("\r");
490 }
491
492 /* We're done */
493 Result = TRUE;
494 break;
495 }
496 }
497
498 /* Return the result */
499 return Result;
500 }
501
502 VOID
503 NTAPI
504 KiDoBugCheckCallbacks(VOID)
505 {
506 PKBUGCHECK_CALLBACK_RECORD CurrentRecord;
507 PLIST_ENTRY ListHead, NextEntry, LastEntry;
508 ULONG_PTR Checksum;
509
510 /* First make sure that the list is Initialized... it might not be */
511 ListHead = &KeBugcheckCallbackListHead;
512 if ((ListHead->Flink) && (ListHead->Blink))
513 {
514 /* Loop the list */
515 LastEntry = ListHead;
516 NextEntry = ListHead->Flink;
517 while (NextEntry != ListHead)
518 {
519 /* Get the reord */
520 CurrentRecord = CONTAINING_RECORD(NextEntry,
521 KBUGCHECK_CALLBACK_RECORD,
522 Entry);
523
524 /* Validate it */
525 if (CurrentRecord->Entry.Blink != LastEntry) return;
526 Checksum = (ULONG_PTR)CurrentRecord->CallbackRoutine;
527 Checksum += (ULONG_PTR)CurrentRecord->Buffer;
528 Checksum += (ULONG_PTR)CurrentRecord->Length;
529 Checksum += (ULONG_PTR)CurrentRecord->Component;
530
531 /* Make sure it's inserted and valitdated */
532 if ((CurrentRecord->State == BufferInserted) &&
533 (CurrentRecord->Checksum == Checksum))
534 {
535 /* Call the routine */
536 CurrentRecord->State = BufferStarted;
537 (CurrentRecord->CallbackRoutine)(CurrentRecord->Buffer,
538 CurrentRecord->Length);
539 CurrentRecord->State = BufferFinished;
540 }
541
542 /* Go to the next entry */
543 LastEntry = NextEntry;
544 NextEntry = NextEntry->Flink;
545 }
546 }
547 }
548
549 DECLSPEC_NORETURN
550 VOID
551 NTAPI
552 KiBugCheckDebugBreak(IN ULONG StatusCode)
553 {
554 /* If KDBG isn't connected, freeze the CPU, otherwise, break */
555 if (KdDebuggerNotPresent) for (;;) KeArchHaltProcessor();
556 DbgBreakPointWithStatus(StatusCode);
557 while (TRUE);
558 }
559
560 PCHAR
561 NTAPI
562 KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode,
563 OUT PCHAR Ansi,
564 IN ULONG Length)
565 {
566 PCHAR p;
567 PWCHAR pw;
568 ULONG i;
569
570 /* Set length and normalize it */
571 i = Unicode->Length / sizeof(WCHAR);
572 i = min(i, Length - 1);
573
574 /* Set source and destination, and copy */
575 pw = Unicode->Buffer;
576 p = Ansi;
577 while (i--) *p++ = (CHAR)*pw++;
578
579 /* Null terminate and return */
580 *p = ANSI_NULL;
581 return Ansi;
582 }
583
584 VOID
585 NTAPI
586 KiDumpParameterImages(IN PCHAR Message,
587 IN PULONG_PTR Parameters,
588 IN ULONG ParameterCount,
589 IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine)
590 {
591 ULONG i;
592 BOOLEAN InSystem;
593 PLDR_DATA_TABLE_ENTRY LdrEntry;
594 PVOID ImageBase;
595 PUNICODE_STRING DriverName;
596 CHAR AnsiName[32];
597 PIMAGE_NT_HEADERS NtHeader;
598 ULONG TimeStamp;
599 BOOLEAN FirstRun = TRUE;
600
601 /* Loop parameters */
602 for (i = 0; i < ParameterCount; i++)
603 {
604 /* Get the base for this parameter */
605 ImageBase = KiPcToFileHeader((PVOID)Parameters[i],
606 &LdrEntry,
607 FALSE,
608 &InSystem);
609 if (!ImageBase)
610 {
611 /* FIXME: Add code to check for unloaded drivers */
612 DPRINT1("Potentially unloaded driver!\n");
613 continue;
614 }
615 else
616 {
617 /* Get the NT Headers and Timestamp */
618 NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
619 TimeStamp = NtHeader->FileHeader.TimeDateStamp;
620
621 /* Convert the driver name */
622 DriverName = &LdrEntry->BaseDllName;
623 ConversionRoutine(&LdrEntry->BaseDllName,
624 AnsiName,
625 sizeof(AnsiName));
626 }
627
628 /* Format driver name */
629 sprintf(Message,
630 "%s** %12s - Address %p base at %p, DateStamp %08lx\n",
631 FirstRun ? "\r\n*":"*",
632 AnsiName,
633 (PVOID)Parameters[i],
634 ImageBase,
635 TimeStamp);
636
637 /* Check if we only had one parameter */
638 if (ParameterCount <= 1)
639 {
640 /* Then just save the name */
641 KiBugCheckDriver = DriverName;
642 }
643 else
644 {
645 /* Otherwise, display the message */
646 InbvDisplayString(Message);
647 }
648
649 /* Loop again */
650 FirstRun = FALSE;
651 }
652 }
653
654 VOID
655 NTAPI
656 KiDisplayBlueScreen(IN ULONG MessageId,
657 IN BOOLEAN IsHardError,
658 IN PCHAR HardErrCaption OPTIONAL,
659 IN PCHAR HardErrMessage OPTIONAL,
660 IN PCHAR Message)
661 {
662 CHAR AnsiName[75];
663
664 /* Check if bootvid is installed */
665 if (InbvIsBootDriverInstalled())
666 {
667 /* Acquire ownership and reset the display */
668 InbvAcquireDisplayOwnership();
669 InbvResetDisplay();
670
671 /* Display blue screen */
672 InbvSolidColorFill(0, 0, 639, 479, 4);
673 InbvSetTextColor(15);
674 InbvInstallDisplayStringFilter(NULL);
675 InbvEnableDisplayString(TRUE);
676 InbvSetScrollRegion(0, 0, 639, 479);
677 }
678
679 /* Check if this is a hard error */
680 if (IsHardError)
681 {
682 /* Display caption and message */
683 if (HardErrCaption) InbvDisplayString(HardErrCaption);
684 if (HardErrMessage) InbvDisplayString(HardErrMessage);
685 }
686
687 /* Begin the display */
688 InbvDisplayString("\r\n");
689
690 /* Print out initial message */
691 KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL);
692 InbvDisplayString("\r\n\r\n");
693
694 /* Check if we have a driver */
695 if (KiBugCheckDriver)
696 {
697 /* Print out into to driver name */
698 KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
699
700 /* Convert and print out driver name */
701 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
702 InbvDisplayString(" ");
703 InbvDisplayString(AnsiName);
704 InbvDisplayString("\r\n\r\n");
705 }
706
707 /* Check if this is the generic message */
708 if (MessageId == BUGCODE_PSS_MESSAGE)
709 {
710 /* It is, so get the bug code string as well */
711 KeGetBugMessageText(KiBugCheckData[0], NULL);
712 InbvDisplayString("\r\n\r\n");
713 }
714
715 /* Print second introduction message */
716 KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL);
717 InbvDisplayString("\r\n\r\n");
718
719 /* Get the bug code string */
720 KeGetBugMessageText(MessageId, NULL);
721 InbvDisplayString("\r\n\r\n");
722
723 /* Print message for technical information */
724 KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
725
726 /* Show the technical Data */
727 sprintf(AnsiName,
728 "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
729 KiBugCheckData[0],
730 (PVOID)KiBugCheckData[1],
731 (PVOID)KiBugCheckData[2],
732 (PVOID)KiBugCheckData[3],
733 (PVOID)KiBugCheckData[4]);
734 InbvDisplayString(AnsiName);
735
736 /* Check if we have a driver*/
737 if (KiBugCheckDriver)
738 {
739 /* Display technical driver data */
740 InbvDisplayString(Message);
741 }
742 else
743 {
744 /* Dump parameter information */
745 KiDumpParameterImages(Message,
746 (PVOID)&KiBugCheckData[1],
747 4,
748 KeBugCheckUnicodeToAnsi);
749 }
750 }
751
752 VOID
753 NTAPI
754 KeBugCheckWithTf(IN ULONG BugCheckCode,
755 IN ULONG_PTR BugCheckParameter1,
756 IN ULONG_PTR BugCheckParameter2,
757 IN ULONG_PTR BugCheckParameter3,
758 IN ULONG_PTR BugCheckParameter4,
759 IN PKTRAP_FRAME TrapFrame)
760 {
761 PKPRCB Prcb = KeGetCurrentPrcb();
762 CONTEXT Context;
763 ULONG MessageId;
764 CHAR AnsiName[128];
765 BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE;
766 PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
767 PVOID Eip = NULL, Memory;
768 PVOID DriverBase;
769 PLDR_DATA_TABLE_ENTRY LdrEntry;
770 PULONG_PTR HardErrorParameters;
771 KIRQL OldIrql;
772 #ifdef CONFIG_SMP
773 LONG i = 0;
774 #endif
775
776 /* Set active bugcheck */
777 KeBugCheckActive = TRUE;
778 KiBugCheckDriver = NULL;
779
780 /* Check if this is power failure simulation */
781 if (BugCheckCode == POWER_FAILURE_SIMULATE)
782 {
783 /* Call the Callbacks and reboot */;
784 KiDoBugCheckCallbacks();
785 HalReturnToFirmware(HalRebootRoutine);
786 }
787
788 /* Save the IRQL and set hardware trigger */
789 Prcb->DebuggerSavedIRQL = KeGetCurrentIrql();
790 InterlockedIncrement((PLONG)&KiHardwareTrigger);
791
792 /* Capture the CPU Context */
793 RtlCaptureContext(&Prcb->ProcessorState.ContextFrame);
794 KiSaveProcessorControlState(&Prcb->ProcessorState);
795 Context = Prcb->ProcessorState.ContextFrame;
796
797 /* FIXME: Call the Watchdog if it's registered */
798
799 /* Check which bugcode this is */
800 switch (BugCheckCode)
801 {
802 /* These bug checks already have detailed messages, keep them */
803 case UNEXPECTED_KERNEL_MODE_TRAP:
804 case DRIVER_CORRUPTED_EXPOOL:
805 case ACPI_BIOS_ERROR:
806 case ACPI_BIOS_FATAL_ERROR:
807 case THREAD_STUCK_IN_DEVICE_DRIVER:
808 case DATA_BUS_ERROR:
809 case FAT_FILE_SYSTEM:
810 case NO_MORE_SYSTEM_PTES:
811 case INACCESSIBLE_BOOT_DEVICE:
812
813 /* Keep the same code */
814 MessageId = BugCheckCode;
815 break;
816
817 /* Check if this is a kernel-mode exception */
818 case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
819 //case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED:
820 case KMODE_EXCEPTION_NOT_HANDLED:
821
822 /* Use the generic text message */
823 MessageId = KMODE_EXCEPTION_NOT_HANDLED;
824 break;
825
826 /* File-system errors */
827 case NTFS_FILE_SYSTEM:
828
829 /* Use the generic message for FAT */
830 MessageId = FAT_FILE_SYSTEM;
831 break;
832
833 /* Check if this is a coruption of the Mm's Pool */
834 case DRIVER_CORRUPTED_MMPOOL:
835
836 /* Use generic corruption message */
837 MessageId = DRIVER_CORRUPTED_EXPOOL;
838 break;
839
840 /* Check if this is a signature check failure */
841 case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
842
843 /* Use the generic corruption message */
844 MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE;
845 break;
846
847 /* All other codes */
848 default:
849
850 /* Use the default bugcheck message */
851 MessageId = BUGCODE_PSS_MESSAGE;
852 break;
853 }
854
855 /* Save bugcheck data */
856 KiBugCheckData[0] = BugCheckCode;
857 KiBugCheckData[1] = BugCheckParameter1;
858 KiBugCheckData[2] = BugCheckParameter2;
859 KiBugCheckData[3] = BugCheckParameter3;
860 KiBugCheckData[4] = BugCheckParameter4;
861
862 /* Now check what bugcheck this is */
863 switch (BugCheckCode)
864 {
865 /* Invalid access to R/O memory or Unhandled KM Exception */
866 case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
867 case ATTEMPTED_WRITE_TO_READONLY_MEMORY:
868 case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY:
869
870 /* Check if we have a trap frame */
871 if (!TrapFrame)
872 {
873 /* Use parameter 3 as a trap frame, if it exists */
874 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
875 }
876
877 /* Check if we got one now and if we need to get EIP */
878 if ((TrapFrame) &&
879 (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
880 {
881 #ifdef _M_IX86
882 /* Get EIP */
883 Eip = (PVOID)TrapFrame->Eip;
884 #elif defined(_M_PPC)
885 Eip = (PVOID)TrapFrame->Dr0; /* srr0 */
886 #endif
887 }
888 break;
889
890 /* Wrong IRQL */
891 case IRQL_NOT_LESS_OR_EQUAL:
892
893 /*
894 * The NT kernel has 3 special sections:
895 * MISYSPTE, POOLMI and POOLCODE. The bug check code can
896 * determine in which of these sections this bugcode happened
897 * and provide a more detailed analysis. For now, we don't.
898 */
899
900 /* Eip is in parameter 4 */
901 Eip = (PVOID)BugCheckParameter4;
902
903 /* Get the driver base */
904 DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
905 if (IsSystem)
906 {
907 /*
908 * The error happened inside the kernel or HAL.
909 * Get the memory address that was being referenced.
910 */
911 Memory = (PVOID)BugCheckParameter1;
912
913 /* Find to which driver it belongs */
914 DriverBase = KiPcToFileHeader(Memory,
915 &LdrEntry,
916 TRUE,
917 &IsSystem);
918 if (DriverBase)
919 {
920 /* Get the driver name and update the bug code */
921 KiBugCheckDriver = &LdrEntry->BaseDllName;
922 KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED;
923 }
924 else
925 {
926 /* Find the driver that unloaded at this address */
927 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
928
929 /* Check if the cause was an unloaded driver */
930 if (KiBugCheckDriver)
931 {
932 /* Update bug check code */
933 KiBugCheckData[0] =
934 SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD;
935 }
936 }
937 }
938 else
939 {
940 /* Update the bug check code */
941 KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
942 }
943
944 /* Clear EIP so we don't look it up later */
945 Eip = NULL;
946 break;
947
948 /* Hard error */
949 case FATAL_UNHANDLED_HARD_ERROR:
950
951 /* Copy bug check data from hard error */
952 HardErrorParameters = (PULONG_PTR)BugCheckParameter2;
953 KiBugCheckData[0] = BugCheckParameter1;
954 KiBugCheckData[1] = HardErrorParameters[0];
955 KiBugCheckData[2] = HardErrorParameters[1];
956 KiBugCheckData[3] = HardErrorParameters[2];
957 KiBugCheckData[4] = HardErrorParameters[3];
958
959 /* Remember that this is hard error and set the caption/message */
960 IsHardError = TRUE;
961 HardErrCaption = (PCHAR)BugCheckParameter3;
962 HardErrMessage = (PCHAR)BugCheckParameter4;
963 break;
964
965 /* Page fault */
966 case PAGE_FAULT_IN_NONPAGED_AREA:
967
968 /* Assume no driver */
969 DriverBase = NULL;
970
971 /* Check if we have a trap frame */
972 if (!TrapFrame)
973 {
974 /* We don't, use parameter 3 if possible */
975 if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
976 }
977
978 /* Check if we have a frame now */
979 if (TrapFrame)
980 {
981 #ifdef _M_IX86
982 /* Get EIP */
983 Eip = (PVOID)TrapFrame->Eip;
984 KiBugCheckData[3] = (ULONG)Eip;
985 #elif defined(_M_PPC)
986 Eip = (PVOID)TrapFrame->Dr0; /* srr0 */
987 KiBugCheckData[3] = (ULONG)Eip;
988 #endif
989
990 /* Find out if was in the kernel or drivers */
991 DriverBase = KiPcToFileHeader(Eip,
992 &LdrEntry,
993 FALSE,
994 &IsSystem);
995 }
996
997 /*
998 * Now we should check if this happened in:
999 * 1) Special Pool 2) Free Special Pool 3) Session Pool
1000 * and update the bugcheck code appropriately.
1001 */
1002
1003 /* Check if we didn't have a driver base */
1004 if (!DriverBase)
1005 {
1006 /* Find the driver that unloaded at this address */
1007 KiBugCheckDriver = NULL; // FIXME: ROS can't locate
1008
1009 /* Check if the cause was an unloaded driver */
1010 if (KiBugCheckDriver)
1011 {
1012 KiBugCheckData[0] =
1013 DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS;
1014 }
1015 }
1016 break;
1017
1018 /* Check if the driver forgot to unlock pages */
1019 case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
1020
1021 /* EIP is in parameter 1 */
1022 Eip = (PVOID)BugCheckParameter1;
1023 break;
1024
1025 /* Check if the driver consumed too many PTEs */
1026 case DRIVER_USED_EXCESSIVE_PTES:
1027
1028 /* Loader entry is in parameter 1 */
1029 LdrEntry = (PVOID)BugCheckParameter1;
1030 KiBugCheckDriver = &LdrEntry->BaseDllName;
1031 break;
1032
1033 /* Check if the driver has a stuck thread */
1034 case THREAD_STUCK_IN_DEVICE_DRIVER:
1035
1036 /* The name is in Parameter 3 */
1037 KiBugCheckDriver = (PVOID)BugCheckParameter3;
1038 break;
1039
1040 /* Anything else */
1041 default:
1042 break;
1043 }
1044
1045 /* Do we have a driver name? */
1046 if (KiBugCheckDriver)
1047 {
1048 /* Convert it to ANSI */
1049 KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
1050 }
1051 else
1052 {
1053 /* Do we have an EIP? */
1054 if (Eip)
1055 {
1056 /* Dump image name */
1057 KiDumpParameterImages(AnsiName,
1058 (PULONG_PTR)&Eip,
1059 1,
1060 KeBugCheckUnicodeToAnsi);
1061 }
1062 }
1063
1064 /* Check if we need to save the context for KD */
1065 #ifdef _WINKD_
1066 if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG)&Context;
1067 #endif
1068
1069 /* Check if a debugger is connected */
1070 if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
1071 {
1072 /* Crash on the debugger console */
1073 DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
1074 " (0x%p,0x%p,0x%p,0x%p)\n\n",
1075 KiBugCheckData[0],
1076 KiBugCheckData[1],
1077 KiBugCheckData[2],
1078 KiBugCheckData[3],
1079 KiBugCheckData[4]);
1080
1081 /* Check if the debugger isn't currently connected */
1082 if (!KdDebuggerNotPresent)
1083 {
1084 /* Check if we have a driver to blame */
1085 if (KiBugCheckDriver)
1086 {
1087 /* Dump it */
1088 DbgPrint("Driver at fault: %s.\n", AnsiName);
1089 }
1090
1091 /* Check if this was a hard error */
1092 if (IsHardError)
1093 {
1094 /* Print caption and message */
1095 if (HardErrCaption) DbgPrint(HardErrCaption);
1096 if (HardErrMessage) DbgPrint(HardErrMessage);
1097 }
1098
1099 /* Break in the debugger */
1100 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST);
1101 }
1102 else
1103 {
1104 /*
1105 * ROS HACK.
1106 * Ok, so debugging is enabled, but KDBG isn't there.
1107 * We'll manually dump the stack for the user.
1108 */
1109 KeRosDumpStackFrames(NULL, 0);
1110
1111 /* ROS HACK 2: Generate something useful for Bugzilla */
1112 KeRosDumpTriageForBugZillaReport();
1113 }
1114 }
1115
1116 /* Raise IRQL to HIGH_LEVEL */
1117 _disable();
1118 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1119
1120 /* Avoid recursion */
1121 if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
1122 {
1123 #ifdef CONFIG_SMP
1124 /* Set CPU that is bug checking now */
1125 KeBugCheckOwner = Prcb->Number;
1126
1127 /* Freeze the other CPUs */
1128 for (i = 0; i < KeNumberProcessors; i++)
1129 {
1130 if (i != (LONG)KeGetCurrentProcessorNumber())
1131 {
1132 /* Send the IPI and give them one second to catch up */
1133 KiIpiSend(1 << i, IPI_FREEZE);
1134 KeStallExecutionProcessor(1000000);
1135 }
1136 }
1137 #endif
1138
1139 /* Display the BSOD */
1140 KiDisplayBlueScreen(MessageId,
1141 IsHardError,
1142 HardErrCaption,
1143 HardErrMessage,
1144 AnsiName);
1145
1146 /* Check if the debugger is disabled but we can enable it */
1147 if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1148 {
1149 /* Enable it */
1150 #ifdef _WINKD_
1151 KdEnableDebuggerWithLock(FALSE);
1152 #endif
1153 }
1154 else
1155 {
1156 /* Otherwise, print the last line */
1157 InbvDisplayString("\r\n");
1158 }
1159
1160 /* Save the context */
1161 Prcb->ProcessorState.ContextFrame = Context;
1162
1163 /* FIXME: Support Triage Dump */
1164
1165 /* FIXME: Write the crash dump */
1166 }
1167 else
1168 {
1169 /* Increase recursion count */
1170 KeBugCheckOwnerRecursionCount++;
1171 if (KeBugCheckOwnerRecursionCount == 2)
1172 {
1173 /* Break in the debugger */
1174 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
1175 }
1176 else if (KeBugCheckOwnerRecursionCount > 2)
1177 {
1178 /* Halt the CPU */
1179 for (;;) KeArchHaltProcessor();
1180 }
1181 }
1182
1183 /* Call the Callbacks */
1184 KiDoBugCheckCallbacks();
1185
1186 /* FIXME: Call Watchdog if enabled */
1187
1188 /* Check if we have to reboot */
1189 if (Reboot)
1190 {
1191 /* Unload symbols */
1192 DbgUnLoadImageSymbols(NULL, NtCurrentProcess(), 0);
1193 HalReturnToFirmware(HalRebootRoutine);
1194 }
1195
1196 /* Attempt to break in the debugger (otherwise halt CPU) */
1197 KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
1198 }
1199
1200 /* PUBLIC FUNCTIONS **********************************************************/
1201
1202 /*
1203 * @unimplemented
1204 */
1205 NTSTATUS
1206 NTAPI
1207 KeInitializeCrashDumpHeader(IN ULONG Type,
1208 IN ULONG Flags,
1209 OUT PVOID Buffer,
1210 IN ULONG BufferSize,
1211 OUT ULONG BufferNeeded OPTIONAL)
1212 {
1213 UNIMPLEMENTED;
1214 return STATUS_UNSUCCESSFUL;
1215 }
1216
1217 /*
1218 * @implemented
1219 */
1220 BOOLEAN
1221 NTAPI
1222 KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)
1223 {
1224 KIRQL OldIrql;
1225 BOOLEAN Status = FALSE;
1226
1227 /* Raise IRQL to High */
1228 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1229
1230 /* Check the Current State */
1231 if (CallbackRecord->State == BufferInserted)
1232 {
1233 /* Reset state and remove from list */
1234 CallbackRecord->State = BufferEmpty;
1235 RemoveEntryList(&CallbackRecord->Entry);
1236 Status = TRUE;
1237 }
1238
1239 /* Lower IRQL and return */
1240 KeLowerIrql(OldIrql);
1241 return Status;
1242 }
1243
1244 /*
1245 * @implemented
1246 */
1247 BOOLEAN
1248 NTAPI
1249 KeDeregisterBugCheckReasonCallback(
1250 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)
1251 {
1252 KIRQL OldIrql;
1253 BOOLEAN Status = FALSE;
1254
1255 /* Raise IRQL to High */
1256 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1257
1258 /* Check the Current State */
1259 if (CallbackRecord->State == BufferInserted)
1260 {
1261 /* Reset state and remove from list */
1262 CallbackRecord->State = BufferEmpty;
1263 RemoveEntryList(&CallbackRecord->Entry);
1264 Status = TRUE;
1265 }
1266
1267 /* Lower IRQL and return */
1268 KeLowerIrql(OldIrql);
1269 return Status;
1270 }
1271
1272 /*
1273 * @unimplemented
1274 */
1275 NTSTATUS
1276 NTAPI
1277 KeDeregisterNmiCallback(PVOID Handle)
1278 {
1279 UNIMPLEMENTED;
1280 return STATUS_UNSUCCESSFUL;
1281 }
1282
1283 /*
1284 * @implemented
1285 */
1286 BOOLEAN
1287 NTAPI
1288 KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
1289 IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
1290 IN PVOID Buffer,
1291 IN ULONG Length,
1292 IN PUCHAR Component)
1293 {
1294 KIRQL OldIrql;
1295 BOOLEAN Status = FALSE;
1296
1297 /* Raise IRQL to High */
1298 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1299
1300 /* Check the Current State first so we don't double-register */
1301 if (CallbackRecord->State == BufferEmpty)
1302 {
1303 /* Set the Callback Settings and insert into the list */
1304 CallbackRecord->Length = Length;
1305 CallbackRecord->Buffer = Buffer;
1306 CallbackRecord->Component = Component;
1307 CallbackRecord->CallbackRoutine = CallbackRoutine;
1308 CallbackRecord->State = BufferInserted;
1309 InsertTailList(&KeBugcheckCallbackListHead, &CallbackRecord->Entry);
1310 Status = TRUE;
1311 }
1312
1313 /* Lower IRQL and return */
1314 KeLowerIrql(OldIrql);
1315 return Status;
1316 }
1317
1318 /*
1319 * @implemented
1320 */
1321 BOOLEAN
1322 NTAPI
1323 KeRegisterBugCheckReasonCallback(
1324 IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
1325 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
1326 IN KBUGCHECK_CALLBACK_REASON Reason,
1327 IN PUCHAR Component)
1328 {
1329 KIRQL OldIrql;
1330 BOOLEAN Status = FALSE;
1331
1332 /* Raise IRQL to High */
1333 KeRaiseIrql(HIGH_LEVEL, &OldIrql);
1334
1335 /* Check the Current State first so we don't double-register */
1336 if (CallbackRecord->State == BufferEmpty)
1337 {
1338 /* Set the Callback Settings and insert into the list */
1339 CallbackRecord->Component = Component;
1340 CallbackRecord->CallbackRoutine = CallbackRoutine;
1341 CallbackRecord->State = BufferInserted;
1342 CallbackRecord->Reason = Reason;
1343 InsertTailList(&KeBugcheckReasonCallbackListHead,
1344 &CallbackRecord->Entry);
1345 Status = TRUE;
1346 }
1347
1348 /* Lower IRQL and return */
1349 KeLowerIrql(OldIrql);
1350 return Status;
1351 }
1352
1353 /*
1354 * @unimplemented
1355 */
1356 PVOID
1357 NTAPI
1358 KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine,
1359 IN PVOID Context)
1360 {
1361 UNIMPLEMENTED;
1362 return NULL;
1363 }
1364
1365 /*
1366 * @implemented
1367 */
1368 VOID
1369 NTAPI
1370 KeBugCheckEx(IN ULONG BugCheckCode,
1371 IN ULONG_PTR BugCheckParameter1,
1372 IN ULONG_PTR BugCheckParameter2,
1373 IN ULONG_PTR BugCheckParameter3,
1374 IN ULONG_PTR BugCheckParameter4)
1375 {
1376 /* Call the internal API */
1377 KeBugCheckWithTf(BugCheckCode,
1378 BugCheckParameter1,
1379 BugCheckParameter2,
1380 BugCheckParameter3,
1381 BugCheckParameter4,
1382 NULL);
1383 }
1384
1385 /*
1386 * @implemented
1387 */
1388 VOID
1389 NTAPI
1390 KeBugCheck(ULONG BugCheckCode)
1391 {
1392 /* Call the internal API */
1393 KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL);
1394 }
1395
1396 /*
1397 * @implemented
1398 */
1399 VOID
1400 NTAPI
1401 KeEnterKernelDebugger(VOID)
1402 {
1403 /* Disable interrupts */
1404 KiHardwareTrigger = 1;
1405 _disable();
1406
1407 /* Check the bugcheck count */
1408 if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
1409 {
1410 /* There was only one, is the debugger disabled? */
1411 if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
1412 {
1413 /* Enable the debugger */
1414 KdInitSystem(0, NULL);
1415 }
1416 }
1417
1418 /* Bugcheck */
1419 KiBugCheckDebugBreak(DBG_STATUS_FATAL);
1420 }
1421
1422 /* EOF */