Merge trunk head (r43756)
[reactos.git] / reactos / ntoskrnl / ke / bug.c
index b6c09d5..f9cc43e 100644 (file)
 /*
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         GPL - See COPYING in the top level directory
  * FILE:            ntoskrnl/ke/bug.c
- * PURPOSE:         Graceful system shutdown if a bug is detected
- *
- * PROGRAMMERS:     Alex Ionescu - Rewrote Bugcheck Routines and implemented Reason Callbacks.
- *                  David Welch (welch@cwcom.net)
- *                  Phillip Susi
+ * PURPOSE:         Bugcheck Support
+ * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  */
 
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 #if defined (ALLOC_PRAGMA)
 #pragma alloc_text(INIT, KiInitializeBugCheck)
 #endif
 
-/* ROS Internal. Please deprecate */
-NTHALAPI
-VOID
-NTAPI
-HalReleaseDisplayOwnership(
-    VOID
-);
+/* GLOBALS *******************************************************************/
 
-extern FAST_MUTEX KernelAddressSpaceLock;
+LIST_ENTRY KeBugcheckCallbackListHead;
+LIST_ENTRY KeBugcheckReasonCallbackListHead;
+KSPIN_LOCK BugCheckCallbackLock;
+ULONG KeBugCheckActive, KeBugCheckOwner;
+LONG KeBugCheckOwnerRecursionCount;
+PRTL_MESSAGE_RESOURCE_DATA KiBugCodeMessages;
+ULONG KeBugCheckCount = 1;
+ULONG KiHardwareTrigger;
+PUNICODE_STRING KiBugCheckDriver;
+ULONG_PTR KiBugCheckData[5];
 
-/* GLOBALS ******************************************************************/
-
-static LIST_ENTRY BugcheckCallbackListHead = {NULL,NULL};
-static LIST_ENTRY BugcheckReasonCallbackListHead = {NULL,NULL};
-static ULONG InBugCheck;
-static PRTL_MESSAGE_RESOURCE_DATA KiBugCodeMessages;
-#ifdef _M_IX86
-static ULONG KeBugCheckCount = 1;
-#endif
+/* Bugzilla Reporting */
+UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion;
+UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion;
 
-/* FUNCTIONS *****************************************************************/
+/* PRIVATE FUNCTIONS *********************************************************/
 
-VOID
-INIT_FUNCTION
+PVOID
 NTAPI
-KiInitializeBugCheck(VOID)
+KiPcToFileHeader(IN PVOID Pc,
+                 OUT PLDR_DATA_TABLE_ENTRY *LdrEntry,
+                 IN BOOLEAN DriversOnly,
+                 OUT PBOOLEAN InKernel)
 {
-    PRTL_MESSAGE_RESOURCE_DATA BugCheckData;
-    LDR_RESOURCE_INFO ResourceInfo;
-    PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
-    NTSTATUS Status;
+    ULONG i = 0;
+    PVOID ImageBase, PcBase = NULL;
+    PLDR_DATA_TABLE_ENTRY Entry;
+    PLIST_ENTRY ListHead, NextEntry;
 
-    /* Initialize Callbadk Listhead and State */
-    InitializeListHead(&BugcheckCallbackListHead);
-    InitializeListHead(&BugcheckReasonCallbackListHead);
-    InBugCheck = 0;
+    /* Check which list we should use */
+    ListHead = (KeLoaderBlock) ? &KeLoaderBlock->LoadOrderListHead :
+                                 &PsLoadedModuleList;
 
-    /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
-    ResourceInfo.Type = 11;
-    ResourceInfo.Name = 1;
-    ResourceInfo.Language = 9;
+    /* Assume no */
+    *InKernel = FALSE;
 
-    /* Do the lookup. */
-    Status = LdrFindResource_U((PVOID)KERNEL_BASE,
-                               &ResourceInfo,
-                               RESOURCE_DATA_LEVEL,
-                               &ResourceDataEntry);
+    /* Set list pointers and make sure it's valid */
+    NextEntry = ListHead->Flink;
+    if (NextEntry)
+    {
+        /* Start loop */
+        while (NextEntry != ListHead)
+        {
+            /* Increase entry */
+            i++;
 
-    /* Make sure it worked */
-    if (NT_SUCCESS(Status)) {
+            /* Check if this is a kernel entry and we only want drivers */
+            if ((i <= 2) && (DriversOnly == TRUE))
+            {
+                /* Skip it */
+                NextEntry = NextEntry->Flink;
+                continue;
+            }
 
-        DPRINT("Found Bugcheck Resource Data!\n");
+            /* Get the loader entry */
+            Entry = CONTAINING_RECORD(NextEntry,
+                                      LDR_DATA_TABLE_ENTRY,
+                                      InLoadOrderLinks);
 
-        /* Now actually get a pointer to it */
-        Status = LdrAccessResource((PVOID)KERNEL_BASE,
-                                   ResourceDataEntry,
-                                   (PVOID*)&BugCheckData,
-                                   NULL);
+            /* Move to the next entry */
+            NextEntry = NextEntry->Flink;
+            ImageBase = Entry->DllBase;
 
-        /* Make sure it worked */
-        if (NT_SUCCESS(Status)) {
+            /* Check if this is the right one */
+            if (((ULONG_PTR)Pc >= (ULONG_PTR)Entry->DllBase) &&
+                ((ULONG_PTR)Pc < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
+            {
+                /* Return this entry */
+                *LdrEntry = Entry;
+                PcBase = ImageBase;
 
-            DPRINT("Got Pointer to Bugcheck Resource Data!\n");
-            KiBugCodeMessages = BugCheckData;
+                /* Check if this was a kernel or HAL entry */
+                if (i <= 2) *InKernel = TRUE;
+                break;
+            }
         }
     }
+
+    /* Return the base address */
+    return PcBase;
 }
 
-/*
- * @implemented
- */
 BOOLEAN
-STDCALL
-KeDeregisterBugCheckCallback(PKBUGCHECK_CALLBACK_RECORD CallbackRecord)
+NTAPI
+KiRosPrintAddress(PVOID address)
 {
-    KIRQL OldIrql;
-    BOOLEAN Status = FALSE;
+    PLIST_ENTRY current_entry;
+    PLDR_DATA_TABLE_ENTRY current;
+    extern LIST_ENTRY PsLoadedModuleList;
+    ULONG_PTR RelativeAddress;
+    ULONG i = 0;
 
-    /* Raise IRQL to High */
-    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+    do
+    {
+        current_entry = PsLoadedModuleList.Flink;
 
-    /* Check the Current State */
-    if (CallbackRecord->State == BufferInserted) {
+        while (current_entry != &PsLoadedModuleList)
+        {
+            current = CONTAINING_RECORD(current_entry,
+                                        LDR_DATA_TABLE_ENTRY,
+                                        InLoadOrderLinks);
 
-        /* Reset state and remove from list */
-        CallbackRecord->State = BufferEmpty;
-        RemoveEntryList(&CallbackRecord->Entry);
+            if (address >= (PVOID)current->DllBase &&
+                address < (PVOID)((ULONG_PTR)current->DllBase +
+                                             current->SizeOfImage))
+            {
+                RelativeAddress = (ULONG_PTR)address -
+                                  (ULONG_PTR)current->DllBase;
+                DbgPrint("<%wZ: %x>", &current->FullDllName, RelativeAddress);
+                return(TRUE);
+            }
+            current_entry = current_entry->Flink;
+        }
+    } while(++i <= 1);
 
-        Status = TRUE;
+    return(FALSE);
+}
+
+PVOID
+NTAPI
+KiRosPcToUserFileHeader(IN PVOID Pc,
+                        OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
+{
+    PVOID ImageBase, PcBase = NULL;
+    PLDR_DATA_TABLE_ENTRY Entry;
+    PLIST_ENTRY ListHead, NextEntry;
+
+    /*
+     * We know this is valid because we should only be called after a
+     * succesfull address from RtlWalkFrameChain for UserMode, which
+     * validates everything for us.
+     */
+    ListHead = &KeGetCurrentThread()->
+               Teb->ProcessEnvironmentBlock->Ldr->InLoadOrderModuleList;
+
+    /* Set list pointers and make sure it's valid */
+    NextEntry = ListHead->Flink;
+    if (NextEntry)
+    {
+        /* Start loop */
+        while (NextEntry != ListHead)
+        {
+            /* Get the loader entry */
+            Entry = CONTAINING_RECORD(NextEntry,
+                                      LDR_DATA_TABLE_ENTRY,
+                                      InLoadOrderLinks);
+
+            /* Move to the next entry */
+            NextEntry = NextEntry->Flink;
+            ImageBase = Entry->DllBase;
+
+            /* Check if this is the right one */
+            if (((ULONG_PTR)Pc >= (ULONG_PTR)Entry->DllBase) &&
+                ((ULONG_PTR)Pc < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
+            {
+                /* Return this entry */
+                *LdrEntry = Entry;
+                PcBase = ImageBase;
+                break;
+            }
+        }
     }
 
-    /* Lower IRQL and return */
-    KeLowerIrql(OldIrql);
-    return Status;
+    /* Return the base address */
+    return PcBase;
 }
 
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-KeDeregisterBugCheckReasonCallback(IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)
+USHORT
+NTAPI
+KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip,
+                               IN ULONG FramesToCapture,
+                               OUT PVOID *BackTrace,
+                               OUT PULONG BackTraceHash OPTIONAL)
 {
-    KIRQL OldIrql;
-    BOOLEAN Status = FALSE;
+    PVOID Frames[2 * 64];
+    ULONG FrameCount;
+    ULONG Hash = 0, i;
 
-    /* Raise IRQL to High */
-    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+    /* Skip a frame for the caller */
+    FramesToSkip++;
 
-    /* Check the Current State */
-    if (CallbackRecord->State == BufferInserted) {
+    /* Don't go past the limit */
+    if ((FramesToCapture + FramesToSkip) >= 128) return 0;
 
-        /* Reset state and remove from list */
-        CallbackRecord->State = BufferEmpty;
-        RemoveEntryList(&CallbackRecord->Entry);
+    /* Do the back trace */
+    FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 1);
 
-        Status = TRUE;
+    /* Make sure we're not skipping all of them */
+    if (FrameCount <= FramesToSkip) return 0;
+
+    /* Loop all the frames */
+    for (i = 0; i < FramesToCapture; i++)
+    {
+        /* Don't go past the limit */
+        if ((FramesToSkip + i) >= FrameCount) break;
+
+        /* Save this entry and hash it */
+        BackTrace[i] = Frames[FramesToSkip + i];
+        Hash += PtrToUlong(BackTrace[i]);
     }
 
-    /* Lower IRQL and return */
-    KeLowerIrql(OldIrql);
-    return Status;
+    /* Write the hash */
+    if (BackTraceHash) *BackTraceHash = Hash;
+
+    /* Clear the other entries and return count */
+    RtlFillMemoryUlong(Frames, 128, 0);
+    return (USHORT)i;
 }
 
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-KeRegisterBugCheckCallback(PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
-                           PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
-                           PVOID Buffer,
-                           ULONG Length,
-                           PUCHAR Component)
+VOID
+FASTCALL
+KeRosDumpStackFrameArray(IN PULONG_PTR Frames,
+                         IN ULONG FrameCount)
 {
-    KIRQL OldIrql;
-    BOOLEAN Status = FALSE;
+    ULONG i;
+    ULONG_PTR Addr;
+    BOOLEAN InSystem;
+    PVOID p;
 
-    /* Raise IRQL to High */
-    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+    /* GCC complaints that it may be used uninitialized */
+    PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
 
-    /* Check the Current State first so we don't double-register */
-    if (CallbackRecord->State == BufferEmpty) {
+    /* Loop them */
+    for (i = 0; i < FrameCount; i++)
+    {
+        /* Get the EIP */
+        Addr = Frames[i];
+        if (!Addr)
+        {
+               break;
+        }
 
-        /* Set the Callback Settings and insert into the list */
-        CallbackRecord->Length = Length;
-        CallbackRecord->Buffer = Buffer;
-        CallbackRecord->Component = Component;
-        CallbackRecord->CallbackRoutine = CallbackRoutine;
-        CallbackRecord->State = BufferInserted;
-        InsertTailList(&BugcheckCallbackListHead, &CallbackRecord->Entry);
+        /* Get the base for this file */
+        if (Addr > (ULONG_PTR)MmHighestUserAddress)
+        {
+            /* We are in kernel */
+            p = KiPcToFileHeader((PVOID)Addr, &LdrEntry, FALSE, &InSystem);
+        }
+        else
+        {
+            /* We are in user land */
+            p = KiRosPcToUserFileHeader((PVOID)Addr, &LdrEntry);
+        }
+        if (p)
+        {
+#ifdef KDBG
+            if (!KdbSymPrintAddress((PVOID)Addr))
+#endif
+            {
+                /* Print out the module name */
+                Addr -= (ULONG_PTR)LdrEntry->DllBase;
+                DbgPrint("<%wZ: %p>", &LdrEntry->FullDllName, (PVOID)Addr);
+            }
+        }
+        else
+        {
+            /* Print only the address */
+            DbgPrint("<%p>", (PVOID)Addr);
+        }
 
-        Status = TRUE;
+        /* Go to the next frame */
+        DbgPrint("\n");
     }
-
-    /* Lower IRQL and return */
-    KeLowerIrql(OldIrql);
-    return Status;
 }
 
-/*
- * @implemented
- */
-BOOLEAN
-STDCALL
-KeRegisterBugCheckReasonCallback(IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
-                                 IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
-                                 IN KBUGCHECK_CALLBACK_REASON Reason,
-                                 IN PUCHAR Component)
+VOID
+NTAPI
+KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL,
+                     IN ULONG FrameCount OPTIONAL)
 {
-    KIRQL OldIrql;
-    BOOLEAN Status = FALSE;
+    ULONG_PTR Frames[32];
+    ULONG RealFrameCount;
 
-    /* Raise IRQL to High */
-    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+    /* If the caller didn't ask, assume 32 frames */
+    if (!FrameCount || FrameCount > 32) FrameCount = 32;
 
-    /* Check the Current State first so we don't double-register */
-    if (CallbackRecord->State == BufferEmpty) {
+    if (Frame)
+    {
+        /* Dump them */
+        KeRosDumpStackFrameArray(Frame, FrameCount);
+    }
+    else
+    {
+        /* Get the current frames (skip the two. One for the dumper, one for the caller) */
+        RealFrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL);
 
-        /* Set the Callback Settings and insert into the list */
-        CallbackRecord->Component = Component;
-        CallbackRecord->CallbackRoutine = CallbackRoutine;
-        CallbackRecord->State = BufferInserted;
-        CallbackRecord->Reason = Reason;
-        InsertTailList(&BugcheckReasonCallbackListHead, &CallbackRecord->Entry);
+        /* Dump them */
+        KeRosDumpStackFrameArray(Frames, RealFrameCount);
 
-        Status = TRUE;
+        /* Count left for user mode? */
+        if (FrameCount - RealFrameCount > 0)
+        {
+            /* Get the current frames */
+            RealFrameCount = KeRosCaptureUserStackBackTrace(-1, FrameCount - RealFrameCount, (PVOID*)Frames, NULL);
+
+            /* Dump them */
+            KeRosDumpStackFrameArray(Frames, RealFrameCount);
+        }
     }
+}
 
-    /* Lower IRQL and return */
-    KeLowerIrql(OldIrql);
-    return Status;
+
+VOID
+NTAPI
+KeRosDumpTriageForBugZillaReport(VOID)
+{
+#if 0
+    extern BOOLEAN KiFastSystemCallDisable, KiSMTProcessorsPresent;
+    extern ULONG KeI386MachineType, MxcsrFeatureMask;
+    extern BOOLEAN Ke386Pae, Ke386NoExecute;
+
+    DbgPrint("ReactOS has crashed! Please go to http://www.reactos.org/bugzilla/enter_bug.cgi to file a bug!\n");
+    DbgPrint("\nHardware Information\n");
+    DbgPrint("Processor Architecture: %d\n"
+             "Feature Bits: %d\n"
+             "System Call Disabled: %d\n"
+             "NPX Present: %d\n"
+             "MXCsr Mask: %d\n"
+             "MXCsr Feature Mask: %d\n"
+             "XMMI Present: %d\n"
+             "FXSR Present: %d\n"
+             "Machine Type: %d\n"
+             "PAE: %d\n"
+             "NX: %d\n"
+             "Processors: %d\n"
+             "Active Processors: %d\n"
+             "Pentium LOCK Bug: %d\n"
+             "Hyperthreading: %d\n"
+             "CPU Manufacturer: %s\n"
+             "CPU Name: %wZ\n"
+             "CPUID: %d\n"
+             "CPU Type: %d\n"
+             "CPU Stepping: %d\n"
+             "CPU Speed: %d\n"
+             "CPU L2 Cache: %d\n"
+             "BIOS Date: %wZ\n"
+             "BIOS Version: %wZ\n"
+             "Video BIOS Date: %wZ\n"
+             "Video BIOS Version: %wZ\n"
+             "Memory: %d\n",
+             KeProcessorArchitecture,
+             KeFeatureBits,
+             KiFastSystemCallDisable,
+             KeI386NpxPresent,
+             KiMXCsrMask,
+             MxcsrFeatureMask,
+             KeI386XMMIPresent,
+             KeI386FxsrPresent,
+             KeI386MachineType,
+             Ke386Pae,
+             Ke386NoExecute,
+             KeNumberProcessors,
+             KeActiveProcessors,
+             KiI386PentiumLockErrataPresent,
+             KiSMTProcessorsPresent,
+             KeGetCurrentPrcb()->VendorString,
+             &KeRosProcessorName,
+             KeGetCurrentPrcb()->CpuID,
+             KeGetCurrentPrcb()->CpuType,
+             KeGetCurrentPrcb()->CpuStep,
+             KeGetCurrentPrcb()->MHz,
+             ((PKIPCR)KeGetPcr())->SecondLevelCacheSize,
+             &KeRosBiosDate,
+             &KeRosBiosVersion,
+             &KeRosVideoBiosDate,
+             &KeRosVideoBiosVersion,
+             MmNumberOfPhysicalPages * PAGE_SIZE);
+#endif
 }
 
 VOID
-STDCALL
-KeGetBugMessageText(ULONG BugCheckCode, PANSI_STRING OutputString)
+INIT_FUNCTION
+NTAPI
+KiInitializeBugCheck(VOID)
+{
+    PRTL_MESSAGE_RESOURCE_DATA BugCheckData;
+    LDR_RESOURCE_INFO ResourceInfo;
+    PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
+    NTSTATUS Status;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+
+    /* Get the kernel entry */
+    LdrEntry = CONTAINING_RECORD(KeLoaderBlock->LoadOrderListHead.Flink,
+                                 LDR_DATA_TABLE_ENTRY,
+                                 InLoadOrderLinks);
+
+    /* Cache the Bugcheck Message Strings. Prepare the Lookup Data */
+    ResourceInfo.Type = 11;
+    ResourceInfo.Name = 1;
+    ResourceInfo.Language = 9;
+
+    /* Do the lookup. */
+    Status = LdrFindResource_U(LdrEntry->DllBase,
+                               &ResourceInfo,
+                               RESOURCE_DATA_LEVEL,
+                               &ResourceDataEntry);
+
+    /* Make sure it worked */
+    if (NT_SUCCESS(Status))
+    {
+        /* Now actually get a pointer to it */
+        Status = LdrAccessResource(LdrEntry->DllBase,
+                                   ResourceDataEntry,
+                                   (PVOID*)&BugCheckData,
+                                   NULL);
+        if (NT_SUCCESS(Status)) KiBugCodeMessages = BugCheckData;
+    }
+}
+
+BOOLEAN
+NTAPI
+KeGetBugMessageText(IN ULONG BugCheckCode,
+                    OUT PANSI_STRING OutputString OPTIONAL)
 {
     ULONG i;
     ULONG IdOffset;
     ULONG_PTR MessageEntry;
     PCHAR BugCode;
+    BOOLEAN Result = FALSE;
+
+    /* Make sure we're not bugchecking too early */
+    if (!KiBugCodeMessages) return Result;
 
-    /* Find the message. This code is based on RtlFindMesssage -- Alex */
-    for (i = 0; i < KiBugCodeMessages->NumberOfBlocks; i++)  
+    /* Find the message. This code is based on RtlFindMesssage */
+    for (i = 0; i < KiBugCodeMessages->NumberOfBlocks; i++)
     {
         /* Check if the ID Matches */
         if ((BugCheckCode >= KiBugCodeMessages->Blocks[i].LowId) &&
-            (BugCheckCode <= KiBugCodeMessages->Blocks[i].HighId)) 
-            {
+            (BugCheckCode <= KiBugCodeMessages->Blocks[i].HighId))
+        {
             /* Get Offset to Entry */
-            MessageEntry = (ULONG_PTR)KiBugCodeMessages + KiBugCodeMessages->Blocks[i].OffsetToEntries;
+            MessageEntry = KiBugCodeMessages->Blocks[i].OffsetToEntries +
+                           (ULONG_PTR)KiBugCodeMessages;
             IdOffset = BugCheckCode - KiBugCodeMessages->Blocks[i].LowId;
 
             /* Get offset to ID */
             for (i = 0; i < IdOffset; i++)
             {
                 /* Advance in the Entries */
-                MessageEntry += ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->Length;
+                MessageEntry += ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->
+                                Length;
             }
 
             /* Get the final Code */
             BugCode = ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->Text;
+            i = strlen(BugCode);
+
+            /* Handle newlines */
+            while ((i > 0) && ((BugCode[i] == '\n') ||
+                               (BugCode[i] == '\r') ||
+                               (BugCode[i] == ANSI_NULL)))
+            {
+                /* Check if we have a string to return */
+                if (!OutputString) BugCode[i] = ANSI_NULL;
+                i--;
+            }
 
-            /* Return it in the OutputString */
-            if (OutputString) 
+            /* Check if caller wants an output string */
+            if (OutputString)
             {
+                /* Return it in the OutputString */
                 OutputString->Buffer = BugCode;
-                OutputString->Length = strlen(BugCode) + 1;
-                OutputString->MaximumLength = strlen(BugCode) + 1;
+                OutputString->Length = (USHORT)i + 1;
+                OutputString->MaximumLength = (USHORT)i + 1;
             }
-            else 
+            else
             {
                 /* Direct Output to Screen */
-                CHAR BugString[100];
-                sprintf(BugString, "%s\n", BugCode);
-                InbvDisplayString(BugString);
-                break;
+                InbvDisplayString(BugCode);
+                InbvDisplayString("\r");
             }
+
+            /* We're done */
+            Result = TRUE;
+            break;
         }
     }
+
+    /* Return the result */
+    return Result;
 }
 
 VOID
-STDCALL
+NTAPI
 KiDoBugCheckCallbacks(VOID)
 {
     PKBUGCHECK_CALLBACK_RECORD CurrentRecord;
-    PLIST_ENTRY ListHead;
-
-    /* FIXME: Check Checksum and add support for WithReason Callbacks */
+    PLIST_ENTRY ListHead, NextEntry, LastEntry;
+    ULONG_PTR Checksum;
 
     /* First make sure that the list is Initialized... it might not be */
-    ListHead = &BugcheckCallbackListHead;
-    if (ListHead->Flink && ListHead->Blink) {
-
+    ListHead = &KeBugcheckCallbackListHead;
+    if ((ListHead->Flink) && (ListHead->Blink))
+    {
         /* Loop the list */
-        LIST_FOR_EACH(CurrentRecord, ListHead, KBUGCHECK_CALLBACK_RECORD, Entry)
+        LastEntry = ListHead;
+        NextEntry = ListHead->Flink;
+        while (NextEntry != ListHead)
         {
-            /* Make sure it's inserted */
-            if (CurrentRecord->State == BufferInserted) {
-
+            /* Get the reord */
+            CurrentRecord = CONTAINING_RECORD(NextEntry,
+                                              KBUGCHECK_CALLBACK_RECORD,
+                                              Entry);
+
+            /* Validate it */
+            if (CurrentRecord->Entry.Blink != LastEntry) return;
+            Checksum = (ULONG_PTR)CurrentRecord->CallbackRoutine;
+            Checksum += (ULONG_PTR)CurrentRecord->Buffer;
+            Checksum += (ULONG_PTR)CurrentRecord->Length;
+            Checksum += (ULONG_PTR)CurrentRecord->Component;
+
+            /* Make sure it's inserted and valitdated */
+            if ((CurrentRecord->State == BufferInserted) &&
+                (CurrentRecord->Checksum == Checksum))
+            {
                 /* Call the routine */
                 CurrentRecord->State = BufferStarted;
                 (CurrentRecord->CallbackRoutine)(CurrentRecord->Buffer,
                                                  CurrentRecord->Length);
                 CurrentRecord->State = BufferFinished;
             }
+
+            /* Go to the next entry */
+            LastEntry = NextEntry;
+            NextEntry = NextEntry->Flink;
         }
     }
 }
 
 VOID
-STDCALL
-KeBugCheckWithTf(ULONG BugCheckCode,
-                 ULONG BugCheckParameter1,
-                 ULONG BugCheckParameter2,
-                 ULONG BugCheckParameter3,
-                 ULONG BugCheckParameter4,
-                 PKTRAP_FRAME Tf)
+NTAPI
+KiBugCheckDebugBreak(IN ULONG StatusCode)
 {
-#ifdef _M_IX86
-    KIRQL OldIrql;
-    BOOLEAN GotExtendedCrashInfo = FALSE;
-    PVOID Address = 0;
-    PLDR_DATA_TABLE_ENTRY CurrentModule = NULL;
-    extern LIST_ENTRY ModuleListHead;
-#if 0
-    CHAR PrintString[100];
-#endif
-    /* Make sure we're switching back to the blue screen and print messages on it */
-    HalReleaseDisplayOwnership();
-    if (!KdpDebugMode.Screen)
+    /*
+     * Wrap this in SEH so we don't crash if
+     * there is no debugger or if it disconnected
+     */
+DoBreak:
+    _SEH2_TRY
     {
-       /* Enable screen debug mode */
-       KdpDebugMode.Screen = TRUE;
-       InitRoutines[0](&DispatchTable[0], 0);
+        /* Breakpoint */
+        DbgBreakPointWithStatus(StatusCode);
     }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        /* No debugger, halt the CPU */
+        HalHaltSystem();
+    }
+    _SEH2_END;
 
-    /* Try to find out who did this. For this, we need a Trap Frame.
-     * Note: Some special BSODs pass the Frame/EIP as a Param. MSDN has the
-     * info so it eventually needs to be supported.
-     */
-    if (Tf) 
+    /* Break again if this wasn't first try */
+    if (StatusCode != DBG_STATUS_BUGCHECK_FIRST) goto DoBreak;
+}
+
+PCHAR
+NTAPI
+KeBugCheckUnicodeToAnsi(IN PUNICODE_STRING Unicode,
+                        OUT PCHAR Ansi,
+                        IN ULONG Length)
+{
+    PCHAR p;
+    PWCHAR pw;
+    ULONG i;
+
+    /* Set length and normalize it */
+    i = Unicode->Length / sizeof(WCHAR);
+    i = min(i, Length - 1);
+
+    /* Set source and destination, and copy */
+    pw = Unicode->Buffer;
+    p = Ansi;
+    while (i--) *p++ = (CHAR)*pw++;
+
+    /* Null terminate and return */
+    *p = ANSI_NULL;
+    return Ansi;
+}
+
+VOID
+NTAPI
+KiDumpParameterImages(IN PCHAR Message,
+                      IN PULONG_PTR Parameters,
+                      IN ULONG ParameterCount,
+                      IN PKE_BUGCHECK_UNICODE_TO_ANSI ConversionRoutine)
+{
+    ULONG i;
+    BOOLEAN InSystem;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    PVOID ImageBase;
+    PUNICODE_STRING DriverName;
+    CHAR AnsiName[32];
+    PIMAGE_NT_HEADERS NtHeader;
+    ULONG TimeStamp;
+    BOOLEAN FirstRun = TRUE;
+
+    /* Loop parameters */
+    for (i = 0; i < ParameterCount; i++)
     {
-        /* For now, get Address from EIP */
-        Address = (PVOID)Tf->Eip;
+        /* Get the base for this parameter */
+        ImageBase = KiPcToFileHeader((PVOID)Parameters[i],
+                                     &LdrEntry,
+                                     FALSE,
+                                     &InSystem);
+        if (!ImageBase)
+        {
+            /* FIXME: Add code to check for unloaded drivers */
+            DPRINT1("Potentially unloaded driver!\n");
+            continue;
+        }
+        else
+        {
+            /* Get the NT Headers and Timestamp */
+            NtHeader = RtlImageNtHeader(LdrEntry->DllBase);
+            TimeStamp = NtHeader->FileHeader.TimeDateStamp;
+
+            /* Convert the driver name */
+            DriverName = &LdrEntry->BaseDllName;
+            ConversionRoutine(&LdrEntry->BaseDllName,
+                              AnsiName,
+                              sizeof(AnsiName));
+        }
 
-        /* Try to get information on the module */
-        LIST_FOR_EACH(CurrentModule, &ModuleListHead, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks)
+        /* Format driver name */
+        sprintf(Message,
+                "%s**  %12s - Address %p base at %p, DateStamp %08lx\n",
+                FirstRun ? "\r\n*":"*",
+                AnsiName,
+                (PVOID)Parameters[i],
+                ImageBase,
+                TimeStamp);
+
+        /* Check if we only had one parameter */
+        if (ParameterCount <= 1)
         {
-            /* Check if this is the right one */
-            if ((Address != NULL && (Address >= (PVOID)CurrentModule->DllBase &&
-                 Address < (PVOID)((ULONG_PTR)CurrentModule->DllBase + CurrentModule->SizeOfImage)))) 
-            {
-                /* We got it */
-                GotExtendedCrashInfo = TRUE;
-                break;
-            }
+            /* Then just save the name */
+            KiBugCheckDriver = DriverName;
+        }
+        else
+        {
+            /* Otherwise, display the message */
+            InbvDisplayString(Message);
         }
+
+        /* Loop again */
+        FirstRun = FALSE;
     }
+}
 
-    /* Raise IRQL to HIGH_LEVEL */
-    Ke386DisableInterrupts();
-    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+VOID
+NTAPI
+KiDisplayBlueScreen(IN ULONG MessageId,
+                    IN BOOLEAN IsHardError,
+                    IN PCHAR HardErrCaption OPTIONAL,
+                    IN PCHAR HardErrMessage OPTIONAL,
+                    IN PCHAR Message)
+{
+    CHAR AnsiName[75];
+
+    /* Check if bootvid is installed */
+    if (InbvIsBootDriverInstalled())
+    {
+        /* Acquire ownership and reset the display */
+        InbvAcquireDisplayOwnership();
+        InbvResetDisplay();
+
+        /* Display blue screen */
+        InbvSolidColorFill(0, 0, 639, 479, 4);
+        InbvSetTextColor(15);
+        InbvInstallDisplayStringFilter(NULL);
+        InbvEnableDisplayString(TRUE);
+        InbvSetScrollRegion(0, 0, 639, 479);
+    }
+
+    /* Check if this is a hard error */
+    if (IsHardError)
+    {
+        /* Display caption and message */
+        if (HardErrCaption) InbvDisplayString(HardErrCaption);
+        if (HardErrMessage) InbvDisplayString(HardErrMessage);
+    }
 
-    /* Unload the Kernel Adress Space if we own it */
-    if (KernelAddressSpaceLock.Owner == KeGetCurrentThread())
-        MmUnlockAddressSpace(MmGetKernelAddressSpace());
+    /* Begin the display */
+    InbvDisplayString("\r\n");
 
-    /* FIXMEs: Use inbv to clear, fill and write to screen. */
+    /* Print out initial message */
+    KeGetBugMessageText(BUGCHECK_MESSAGE_INTRO, NULL);
+    InbvDisplayString("\r\n\r\n");
 
-    /* Show the STOP Message */
-#if 0
-    InbvDisplayString("A problem has been detected and ReactOS has been shut down to prevent "
-                      "damage to your computer.\n\n");
-#else
-    DbgPrint("A problem has been detected and ReactOS has been shut down to prevent "
-             "damage to your computer.\n\n");
-#endif
-    /* Show the module name of who caused this */
-    if (GotExtendedCrashInfo) 
+    /* Check if we have a driver */
+    if (KiBugCheckDriver)
     {
-#if 0
-        sprintf(PrintString, 
-                "The problem seems to be caused by the following file: %wZ\n\n",
-                &CurrentModule->BaseDllName);
-        InbvDisplayString(PrintString);
-#else
-        DbgPrint("The problem seems to be caused by the following file: %wZ\n\n",
-                 &CurrentModule->BaseDllName);
-#endif
+        /* Print out into to driver name */
+        KeGetBugMessageText(BUGCODE_ID_DRIVER, NULL);
+
+        /* Convert and print out driver name */
+        KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
+        InbvDisplayString(" ");
+        InbvDisplayString(AnsiName);
+        InbvDisplayString("\r\n\r\n");
+    }
+
+    /* Check if this is the generic message */
+    if (MessageId == BUGCODE_PSS_MESSAGE)
+    {
+        /* It is, so get the bug code string as well */
+        KeGetBugMessageText(KiBugCheckData[0], NULL);
+        InbvDisplayString("\r\n\r\n");
     }
 
-    /* Find the Bug Code String */
-    KeGetBugMessageText(BugCheckCode, NULL);
+    /* Print second introduction message */
+    KeGetBugMessageText(PSS_MESSAGE_INTRO, NULL);
+    InbvDisplayString("\r\n\r\n");
+
+    /* Get the bug code string */
+    KeGetBugMessageText(MessageId, NULL);
+    InbvDisplayString("\r\n\r\n");
+
+    /* Print message for technical information */
+    KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
+
+    /* Show the technical Data */
+    sprintf(AnsiName,
+            "\r\n\r\n*** STOP: 0x%p (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
+            (PVOID)KiBugCheckData[0],
+            (PVOID)KiBugCheckData[1],
+            (PVOID)KiBugCheckData[2],
+            (PVOID)KiBugCheckData[3],
+            (PVOID)KiBugCheckData[4]);
+    InbvDisplayString(AnsiName);
+
+    /* Check if we have a driver*/
+    if (KiBugCheckDriver)
+    {
+        /* Display technical driver data */
+        InbvDisplayString(Message);
+    }
+    else
+    {
+        /* Dump parameter information */
+        KiDumpParameterImages(Message,
+                              (PVOID)&KiBugCheckData[1],
+                              4,
+                              KeBugCheckUnicodeToAnsi);
+    }
+}
 
-    /* Show the techincal Data */
-#if 0
-    sprintf(PrintString,
-            "Technical information:\n\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\n\n",
-            BugCheckCode,
-            (PVOID)BugCheckParameter1,
-            (PVOID)BugCheckParameter2,
-            (PVOID)BugCheckParameter3,
-            (PVOID)BugCheckParameter4);
-    InbvDisplayString(PrintString);
-#else
-    DbgPrint("Technical information:\n\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\n\n",
-             BugCheckCode,
-            (PVOID)BugCheckParameter1,
-            (PVOID)BugCheckParameter2,
-            (PVOID)BugCheckParameter3,
-            (PVOID)BugCheckParameter4);
+VOID
+NTAPI
+KeBugCheckWithTf(IN ULONG BugCheckCode,
+                 IN ULONG_PTR BugCheckParameter1,
+                 IN ULONG_PTR BugCheckParameter2,
+                 IN ULONG_PTR BugCheckParameter3,
+                 IN ULONG_PTR BugCheckParameter4,
+                 IN PKTRAP_FRAME TrapFrame)
+{
+    PKPRCB Prcb = KeGetCurrentPrcb();
+    CONTEXT Context;
+    ULONG MessageId;
+    CHAR AnsiName[128];
+    BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE;
+    PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
+    PVOID Pc = NULL, Memory;
+    PVOID DriverBase;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
+    PULONG_PTR HardErrorParameters;
+    KIRQL OldIrql;
+#ifdef CONFIG_SMP
+    LONG i = 0;
 #endif
-    /* Show the module name and more data of who caused this */
-    if (GotExtendedCrashInfo) 
+
+    /* Set active bugcheck */
+    KeBugCheckActive = TRUE;
+    KiBugCheckDriver = NULL;
+
+    /* Check if this is power failure simulation */
+    if (BugCheckCode == POWER_FAILURE_SIMULATE)
     {
-#if 0
-        sprintf(PrintString,
-                "***    %wZ - Address 0x%p base at 0x%p, DateStamp 0x%x\n\n",
-                &CurrentModule->BaseDllName,
-                Address,
-                (PVOID)CurrentModule->DllBase,
-                0);
-        InbvDisplayString(PrintString);
-#else
-        DbgPrint("***    %wZ - Address 0x%p base at 0x%p, DateStamp 0x%x\n\n",
-                 &CurrentModule->BaseDllName,
-                 Address,
-                 (PVOID)CurrentModule->DllBase,
-                 0);
+        /* Call the Callbacks and reboot */;
+        KiDoBugCheckCallbacks();
+        HalReturnToFirmware(HalRebootRoutine);
+    }
+
+    /* Save the IRQL and set hardware trigger */
+    Prcb->DebuggerSavedIRQL = KeGetCurrentIrql();
+    InterlockedIncrement((PLONG)&KiHardwareTrigger);
+
+    /* Capture the CPU Context */
+    RtlCaptureContext(&Prcb->ProcessorState.ContextFrame);
+    KiSaveProcessorControlState(&Prcb->ProcessorState);
+    Context = Prcb->ProcessorState.ContextFrame;
+
+    /* FIXME: Call the Watchdog if it's registered */
+
+    /* Check which bugcode this is */
+    switch (BugCheckCode)
+    {
+        /* These bug checks already have detailed messages, keep them */
+        case UNEXPECTED_KERNEL_MODE_TRAP:
+        case DRIVER_CORRUPTED_EXPOOL:
+        case ACPI_BIOS_ERROR:
+        case ACPI_BIOS_FATAL_ERROR:
+        case THREAD_STUCK_IN_DEVICE_DRIVER:
+        case DATA_BUS_ERROR:
+        case FAT_FILE_SYSTEM:
+        case NO_MORE_SYSTEM_PTES:
+        case INACCESSIBLE_BOOT_DEVICE:
+
+            /* Keep the same code */
+            MessageId = BugCheckCode;
+            break;
+
+        /* Check if this is a kernel-mode exception */
+        case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
+        //case SYSTEM_THREAD_EXCEPTION_NOT_HANDLED:
+        case KMODE_EXCEPTION_NOT_HANDLED:
+
+            /* Use the generic text message */
+            MessageId = KMODE_EXCEPTION_NOT_HANDLED;
+            break;
+
+        /* File-system errors */
+        case NTFS_FILE_SYSTEM:
+
+            /* Use the generic message for FAT */
+            MessageId = FAT_FILE_SYSTEM;
+            break;
+
+        /* Check if this is a coruption of the Mm's Pool */
+        case DRIVER_CORRUPTED_MMPOOL:
+
+            /* Use generic corruption message */
+            MessageId = DRIVER_CORRUPTED_EXPOOL;
+            break;
+
+        /* Check if this is a signature check failure */
+        case STATUS_SYSTEM_IMAGE_BAD_SIGNATURE:
+
+            /* Use the generic corruption message */
+            MessageId = BUGCODE_PSS_MESSAGE_SIGNATURE;
+            break;
+
+        /* All other codes */
+        default:
+
+            /* Use the default bugcheck message */
+            MessageId = BUGCODE_PSS_MESSAGE;
+            break;
+    }
+
+    /* Save bugcheck data */
+    KiBugCheckData[0] = BugCheckCode;
+    KiBugCheckData[1] = BugCheckParameter1;
+    KiBugCheckData[2] = BugCheckParameter2;
+    KiBugCheckData[3] = BugCheckParameter3;
+    KiBugCheckData[4] = BugCheckParameter4;
+
+    /* Now check what bugcheck this is */
+    switch (BugCheckCode)
+    {
+        /* Invalid access to R/O memory or Unhandled KM Exception */
+        case KERNEL_MODE_EXCEPTION_NOT_HANDLED:
+        case ATTEMPTED_WRITE_TO_READONLY_MEMORY:
+        case ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY:
+
+            /* Check if we have a trap frame */
+            if (!TrapFrame)
+            {
+                /* Use parameter 3 as a trap frame, if it exists */
+                if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
+            }
+
+            /* Check if we got one now and if we need to get the Program Counter */
+            if ((TrapFrame) &&
+                (BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
+            {
+                /* Get the Program Counter */
+                Pc = (PVOID)KeGetTrapFramePc(TrapFrame);
+            }
+            break;
+
+        /* Wrong IRQL */
+        case IRQL_NOT_LESS_OR_EQUAL:
+
+            /*
+             * The NT kernel has 3 special sections:
+             * MISYSPTE, POOLMI and POOLCODE. The bug check code can
+             * determine in which of these sections this bugcode happened
+             * and provide a more detailed analysis. For now, we don't.
+             */
+
+            /* Program Counter is in parameter 4 */
+            Pc = (PVOID)BugCheckParameter4;
+
+            /* Get the driver base */
+            DriverBase = KiPcToFileHeader(Pc,
+                                          &LdrEntry,
+                                          FALSE,
+                                          &IsSystem);
+            if (IsSystem)
+            {
+                /*
+                 * The error happened inside the kernel or HAL.
+                 * Get the memory address that was being referenced.
+                 */
+                Memory = (PVOID)BugCheckParameter1;
+
+                /* Find to which driver it belongs */
+                DriverBase = KiPcToFileHeader(Memory,
+                                              &LdrEntry,
+                                              TRUE,
+                                              &IsSystem);
+                if (DriverBase)
+                {
+                    /* Get the driver name and update the bug code */
+                    KiBugCheckDriver = &LdrEntry->BaseDllName;
+                    KiBugCheckData[0] = DRIVER_PORTION_MUST_BE_NONPAGED;
+                }
+                else
+                {
+                    /* Find the driver that unloaded at this address */
+                    KiBugCheckDriver = NULL; // FIXME: ROS can't locate
+
+                    /* Check if the cause was an unloaded driver */
+                    if (KiBugCheckDriver)
+                    {
+                        /* Update bug check code */
+                        KiBugCheckData[0] =
+                            SYSTEM_SCAN_AT_RAISED_IRQL_CAUGHT_IMPROPER_DRIVER_UNLOAD;
+                    }
+                }
+            }
+            else
+            {
+                /* Update the bug check code */
+                KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
+            }
+
+            /* Clear Pc so we don't look it up later */
+            Pc = NULL;
+            break;
+
+        /* Hard error */
+        case FATAL_UNHANDLED_HARD_ERROR:
+
+            /* Copy bug check data from hard error */
+            HardErrorParameters = (PULONG_PTR)BugCheckParameter2;
+            KiBugCheckData[0] = BugCheckParameter1;
+            KiBugCheckData[1] = HardErrorParameters[0];
+            KiBugCheckData[2] = HardErrorParameters[1];
+            KiBugCheckData[3] = HardErrorParameters[2];
+            KiBugCheckData[4] = HardErrorParameters[3];
+
+            /* Remember that this is hard error and set the caption/message */
+            IsHardError = TRUE;
+            HardErrCaption = (PCHAR)BugCheckParameter3;
+            HardErrMessage = (PCHAR)BugCheckParameter4;
+            break;
+
+        /* Page fault */
+        case PAGE_FAULT_IN_NONPAGED_AREA:
+
+            /* Assume no driver */
+            DriverBase = NULL;
+
+            /* Check if we have a trap frame */
+            if (!TrapFrame)
+            {
+                /* We don't, use parameter 3 if possible */
+                if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
+            }
+
+            /* Check if we have a frame now */
+            if (TrapFrame)
+            {
+                /* Get the Program Counter */
+                Pc = (PVOID)KeGetTrapFramePc(TrapFrame);
+                KiBugCheckData[3] = (ULONG_PTR)Pc;
+
+                /* Find out if was in the kernel or drivers */
+                DriverBase = KiPcToFileHeader(Pc,
+                                              &LdrEntry,
+                                              FALSE,
+                                              &IsSystem);
+            }
+
+            /*
+             * Now we should check if this happened in:
+             * 1) Special Pool 2) Free Special Pool 3) Session Pool
+             * and update the bugcheck code appropriately.
+             */
+
+            /* Check if we didn't have a driver base */
+            if (!DriverBase)
+            {
+                /* Find the driver that unloaded at this address */
+                KiBugCheckDriver = NULL; // FIXME: ROS can't locate
+
+                /* Check if the cause was an unloaded driver */
+                if (KiBugCheckDriver)
+                {
+                    KiBugCheckData[0] =
+                        DRIVER_UNLOADED_WITHOUT_CANCELLING_PENDING_OPERATIONS;
+                }
+            }
+            break;
+
+        /* Check if the driver forgot to unlock pages */
+        case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
+
+            /* Program Counter is in parameter 1 */
+            Pc = (PVOID)BugCheckParameter1;
+            break;
+
+        /* Check if the driver consumed too many PTEs */
+        case DRIVER_USED_EXCESSIVE_PTES:
+
+            /* Loader entry is in parameter 1 */
+            LdrEntry = (PVOID)BugCheckParameter1;
+            KiBugCheckDriver = &LdrEntry->BaseDllName;
+            break;
+
+        /* Check if the driver has a stuck thread */
+        case THREAD_STUCK_IN_DEVICE_DRIVER:
+
+            /* The name is in Parameter 3 */
+            KiBugCheckDriver = (PVOID)BugCheckParameter3;
+            break;
+
+        /* Anything else */
+        default:
+            break;
+    }
+
+    /* Do we have a driver name? */
+    if (KiBugCheckDriver)
+    {
+        /* Convert it to ANSI */
+        KeBugCheckUnicodeToAnsi(KiBugCheckDriver, AnsiName, sizeof(AnsiName));
+    }
+    else
+    {
+        /* Do we have a Program Counter? */
+        if (Pc)
+        {
+            /* Dump image name */
+            KiDumpParameterImages(AnsiName,
+                                  (PULONG_PTR)&Pc,
+                                  1,
+                                  KeBugCheckUnicodeToAnsi);
+        }
+    }
+
+    /* Check if we need to save the context for KD */
+#ifdef _WINKD_
+    if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG_PTR)&Context;
 #endif
+
+    /* Check if a debugger is connected */
+    if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
+    {
+        /* Crash on the debugger console */
+        DbgPrint("\n*** Fatal System Error: 0x%08lx\n"
+                 "                       (0x%p,0x%p,0x%p,0x%p)\n\n",
+                 KiBugCheckData[0],
+                 KiBugCheckData[1],
+                 KiBugCheckData[2],
+                 KiBugCheckData[3],
+                 KiBugCheckData[4]);
+
+        /* Check if the debugger isn't currently connected */
+        if (!KdDebuggerNotPresent)
+        {
+            /* Check if we have a driver to blame */
+            if (KiBugCheckDriver)
+            {
+                /* Dump it */
+                DbgPrint("Driver at fault: %s.\n", AnsiName);
+            }
+
+            /* Check if this was a hard error */
+            if (IsHardError)
+            {
+                /* Print caption and message */
+                if (HardErrCaption) DbgPrint(HardErrCaption);
+                if (HardErrMessage) DbgPrint(HardErrMessage);
+            }
+
+            /* Break in the debugger */
+            KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_FIRST);
+        }
+        else
+        {
+            /*
+             * ROS HACK.
+             * Ok, so debugging is enabled, but KDBG isn't there.
+             * We'll manually dump the stack for the user.
+             */
+            KeRosDumpStackFrames(NULL, 0);
+
+            /* ROS HACK 2: Generate something useful for Bugzilla */
+            KeRosDumpTriageForBugZillaReport();
+        }
     }
 
-    /* There can only be one Bugcheck per Bootup */
-    if (!InterlockedDecrement((PLONG)&KeBugCheckCount)) 
+    /* Raise IRQL to HIGH_LEVEL */
+    _disable();
+    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+    /* Avoid recursion */
+    if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
     {
 #ifdef CONFIG_SMP
-        LONG i;
+        /* Set CPU that is bug checking now */
+        KeBugCheckOwner = Prcb->Number;
+
         /* Freeze the other CPUs */
-        for (i = 0; i < KeNumberProcessors; i++) 
+        for (i = 0; i < KeNumberProcessors; i++)
         {
             if (i != (LONG)KeGetCurrentProcessorNumber())
             {
                 /* Send the IPI and give them one second to catch up */
-                KiIpiSendRequest(1 << i, IPI_FREEZE);
+                KiIpiSend(1 << i, IPI_FREEZE);
                 KeStallExecutionProcessor(1000000);
             }
         }
 #endif
-        /* Check if we got a Trap Frame */
-        if (Tf) 
-        {
-            /* Dump it */
-            KiDumpTrapFrame(Tf, BugCheckParameter1, BugCheckParameter2);
-        } 
-        else 
+
+        /* Display the BSOD */
+        KiDisplayBlueScreen(MessageId,
+                            IsHardError,
+                            HardErrCaption,
+                            HardErrMessage,
+                            AnsiName);
+
+        /* Check if the debugger is disabled but we can enable it */
+        if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
         {
-            /* We can only dump the frames */
-#if defined(__GNUC__)
-            KeDumpStackFrames((PULONG)__builtin_frame_address(0));
-#elif defined(_MSC_VER)
-            __asm push ebp
-            __asm call KeDumpStackFrames
-            __asm add esp, 4
-#else
-#error Unknown compiler for inline assembler
+            /* Enable it */
+#ifdef _WINKD_
+            KdEnableDebuggerWithLock(FALSE);
 #endif
         }
+        else
+        {
+            /* Otherwise, print the last line */
+            InbvDisplayString("\r\n");
+        }
 
-        /* Call the Callbacks */;
-        KiDoBugCheckCallbacks();
+        /* Save the context */
+        Prcb->ProcessorState.ContextFrame = Context;
 
-        /* Dump the BSOD to the Paging File */
-        MmDumpToPagingFile(BugCheckCode,
-                           BugCheckParameter1,
-                           BugCheckParameter2,
-                           BugCheckParameter3,
-                           BugCheckParameter4,
-                           Tf);
+        /* FIXME: Support Triage Dump */
 
-        /* Wake up the Debugger */
-        if (KdDebuggerEnabled) 
+        /* FIXME: Write the crash dump */
+    }
+    else
+    {
+        /* Increase recursion count */
+        KeBugCheckOwnerRecursionCount++;
+        if (KeBugCheckOwnerRecursionCount == 2)
+        {
+            /* Break in the debugger */
+            KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
+        }
+        else if (KeBugCheckOwnerRecursionCount > 2)
         {
-            Ke386EnableInterrupts();
-            DbgBreakPointWithStatus(DBG_STATUS_BUGCHECK_SECOND);
-            Ke386DisableInterrupts();
+            /* Halt execution */
+            while (TRUE);
         }
     }
 
-    /* Halt this CPU now */
-    for (;;) Ke386HaltProcessor();
-#elif defined(_M_PPC)
-    for (;;);
-#endif
+    /* Call the Callbacks */
+    KiDoBugCheckCallbacks();
+
+    /* FIXME: Call Watchdog if enabled */
+
+    /* Check if we have to reboot */
+    if (Reboot)
+    {
+        /* Unload symbols */
+        DbgUnLoadImageSymbols(NULL, (PVOID)MAXULONG_PTR, 0);
+        HalReturnToFirmware(HalRebootRoutine);
+    }
+
+    /* Attempt to break in the debugger (otherwise halt CPU) */
+    KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
+
+    /* Shouldn't get here */
+    while (TRUE);
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+KeInitializeCrashDumpHeader(IN ULONG Type,
+                            IN ULONG Flags,
+                            OUT PVOID Buffer,
+                            IN ULONG BufferSize,
+                            OUT ULONG BufferNeeded OPTIONAL)
+{
+    UNIMPLEMENTED;
+    return STATUS_UNSUCCESSFUL;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+KeDeregisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord)
+{
+    KIRQL OldIrql;
+    BOOLEAN Status = FALSE;
+
+    /* Raise IRQL to High */
+    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+    /* Check the Current State */
+    if (CallbackRecord->State == BufferInserted)
+    {
+        /* Reset state and remove from list */
+        CallbackRecord->State = BufferEmpty;
+        RemoveEntryList(&CallbackRecord->Entry);
+        Status = TRUE;
+    }
+
+    /* Lower IRQL and return */
+    KeLowerIrql(OldIrql);
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+KeDeregisterBugCheckReasonCallback(
+    IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord)
+{
+    KIRQL OldIrql;
+    BOOLEAN Status = FALSE;
+
+    /* Raise IRQL to High */
+    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+    /* Check the Current State */
+    if (CallbackRecord->State == BufferInserted)
+    {
+        /* Reset state and remove from list */
+        CallbackRecord->State = BufferEmpty;
+        RemoveEntryList(&CallbackRecord->Entry);
+        Status = TRUE;
+    }
+
+    /* Lower IRQL and return */
+    KeLowerIrql(OldIrql);
+    return Status;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+KeDeregisterNmiCallback(PVOID Handle)
+{
+    UNIMPLEMENTED;
+    return STATUS_UNSUCCESSFUL;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
+                           IN PKBUGCHECK_CALLBACK_ROUTINE CallbackRoutine,
+                           IN PVOID Buffer,
+                           IN ULONG Length,
+                           IN PUCHAR Component)
+{
+    KIRQL OldIrql;
+    BOOLEAN Status = FALSE;
+
+    /* Raise IRQL to High */
+    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+    /* Check the Current State first so we don't double-register */
+    if (CallbackRecord->State == BufferEmpty)
+    {
+        /* Set the Callback Settings and insert into the list */
+        CallbackRecord->Length = Length;
+        CallbackRecord->Buffer = Buffer;
+        CallbackRecord->Component = Component;
+        CallbackRecord->CallbackRoutine = CallbackRoutine;
+        CallbackRecord->State = BufferInserted;
+        InsertTailList(&KeBugcheckCallbackListHead, &CallbackRecord->Entry);
+        Status = TRUE;
+    }
+
+    /* Lower IRQL and return */
+    KeLowerIrql(OldIrql);
+    return Status;
+}
+
+/*
+ * @implemented
+ */
+BOOLEAN
+NTAPI
+KeRegisterBugCheckReasonCallback(
+    IN PKBUGCHECK_REASON_CALLBACK_RECORD CallbackRecord,
+    IN PKBUGCHECK_REASON_CALLBACK_ROUTINE CallbackRoutine,
+    IN KBUGCHECK_CALLBACK_REASON Reason,
+    IN PUCHAR Component)
+{
+    KIRQL OldIrql;
+    BOOLEAN Status = FALSE;
+
+    /* Raise IRQL to High */
+    KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+    /* Check the Current State first so we don't double-register */
+    if (CallbackRecord->State == BufferEmpty)
+    {
+        /* Set the Callback Settings and insert into the list */
+        CallbackRecord->Component = Component;
+        CallbackRecord->CallbackRoutine = CallbackRoutine;
+        CallbackRecord->State = BufferInserted;
+        CallbackRecord->Reason = Reason;
+        InsertTailList(&KeBugcheckReasonCallbackListHead,
+                       &CallbackRecord->Entry);
+        Status = TRUE;
+    }
+
+    /* Lower IRQL and return */
+    KeLowerIrql(OldIrql);
+    return Status;
+}
+
+/*
+ * @unimplemented
+ */
+PVOID
+NTAPI
+KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine,
+                      IN PVOID Context)
+{
+    UNIMPLEMENTED;
+    return NULL;
 }
 
 /*
  * @implemented
- *
- * FUNCTION: Brings the system down in a controlled manner when an
- * inconsistency that might otherwise cause corruption has been detected
- * ARGUMENTS:
- *           BugCheckCode = Specifies the reason for the bug check
- *           BugCheckParameter[1-4] = Additional information about bug
- * RETURNS: Doesn't
  */
 VOID
-STDCALL
-KeBugCheckEx(ULONG BugCheckCode,
-             ULONG BugCheckParameter1,
-             ULONG BugCheckParameter2,
-             ULONG BugCheckParameter3,
-             ULONG BugCheckParameter4)
+NTAPI
+KeBugCheckEx(IN ULONG BugCheckCode,
+             IN ULONG_PTR BugCheckParameter1,
+             IN ULONG_PTR BugCheckParameter2,
+             IN ULONG_PTR BugCheckParameter3,
+             IN ULONG_PTR BugCheckParameter4)
 {
-    /* Call the Trap Frame version without a Trap Frame */
+    /* Call the internal API */
     KeBugCheckWithTf(BugCheckCode,
                      BugCheckParameter1,
                      BugCheckParameter2,
@@ -506,18 +1396,39 @@ KeBugCheckEx(ULONG BugCheckCode,
 
 /*
  * @implemented
- *
- * FUNCTION: Brings the system down in a controlled manner when an
- * inconsistency that might otherwise cause corruption has been detected
- * ARGUMENTS:
- *           BugCheckCode = Specifies the reason for the bug check
- * RETURNS: Doesn't
  */
 VOID
-STDCALL
+NTAPI
 KeBugCheck(ULONG BugCheckCode)
 {
-    KeBugCheckEx(BugCheckCode, 0, 0, 0, 0);
+    /* Call the internal API */
+    KeBugCheckWithTf(BugCheckCode, 0, 0, 0, 0, NULL);
+}
+
+/*
+ * @implemented
+ */
+VOID
+NTAPI
+KeEnterKernelDebugger(VOID)
+{
+    /* Disable interrupts */
+    KiHardwareTrigger = 1;
+    _disable();
+
+    /* Check the bugcheck count */
+    if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
+    {
+        /* There was only one, is the debugger disabled? */
+        if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
+        {
+            /* Enable the debugger */
+            KdInitSystem(0, NULL);
+        }
+    }
+
+    /* Break in the debugger */
+    KiBugCheckDebugBreak(DBG_STATUS_FATAL);
 }
 
 /* EOF */