- Fix KiDispatchException to unmask KI_EXCEPTION_INTERNAL when setting the exception...
[reactos.git] / reactos / ntoskrnl / ke / bug.c
index 4ec0d27..dd19977 100644 (file)
 #pragma alloc_text(INIT, KiInitializeBugCheck)
 #endif
 
-/* ROS Internal. Please deprecate */
-NTHALAPI
-VOID
-NTAPI
-HalReleaseDisplayOwnership(
-    VOID
-);
-
-extern FAST_MUTEX KernelAddressSpaceLock;
-
 /* GLOBALS *******************************************************************/
 
-LIST_ENTRY BugcheckCallbackListHead = {NULL,NULL};
-LIST_ENTRY BugcheckReasonCallbackListHead = {NULL,NULL};
+LIST_ENTRY KeBugcheckCallbackListHead;
+LIST_ENTRY KeBugcheckReasonCallbackListHead;
+KSPIN_LOCK BugCheckCallbackLock;
 ULONG KeBugCheckActive, KeBugCheckOwner;
 LONG KeBugCheckOwnerRecursionCount;
 PRTL_MESSAGE_RESOURCE_DATA KiBugCodeMessages;
@@ -38,13 +29,6 @@ ULONG KiHardwareTrigger;
 PUNICODE_STRING KiBugCheckDriver;
 ULONG_PTR KiBugCheckData[5];
 
-typedef PCHAR
-(NTAPI *PKE_BUGCHECK_UNICODE_TO_ANSI)(
-    IN PUNICODE_STRING Unicode,
-    IN PCHAR Ansi,
-    IN ULONG Length
-);
-
 /* PRIVATE FUNCTIONS *********************************************************/
 
 BOOLEAN
@@ -53,15 +37,15 @@ KiRosPrintAddress(PVOID address)
 {
     PLIST_ENTRY current_entry;
     PLDR_DATA_TABLE_ENTRY current;
-    extern LIST_ENTRY ModuleListHead;
+    extern LIST_ENTRY PsLoadedModuleList;
     ULONG_PTR RelativeAddress;
     ULONG i = 0;
 
     do
     {
-        current_entry = ModuleListHead.Flink;
+        current_entry = PsLoadedModuleList.Flink;
 
-        while (current_entry != &ModuleListHead)
+        while (current_entry != &PsLoadedModuleList)
         {
             current = CONTAINING_RECORD(current_entry,
                                         LDR_DATA_TABLE_ENTRY,
@@ -83,83 +67,22 @@ KiRosPrintAddress(PVOID address)
     return(FALSE);
 }
 
-ULONG
-NTAPI
-KeRosGetStackFrames(PULONG Frames,
-                    ULONG FrameCount)
-{
-    ULONG Count = 0;
-    PULONG StackBase, StackEnd, Frame;
-    MEMORY_BASIC_INFORMATION mbi;
-    ULONG ResultLength = sizeof(mbi);
-    NTSTATUS Status;
-
-    _SEH_TRY
-    {
-#if defined __GNUC__
-        __asm__("mov %%ebp, %0" : "=r" (Frame) : );
-#elif defined(_MSC_VER)
-        __asm mov [Frame], ebp
-#endif
-
-            Status = MiQueryVirtualMemory (
-            (HANDLE)-1,
-            Frame,
-            MemoryBasicInformation,
-            &mbi,
-            sizeof(mbi),
-            &ResultLength );
-        if ( !NT_SUCCESS(Status) )
-        {
-            DPRINT1("Can't get stack frames: MiQueryVirtualMemory() failed: %x\n", Status );
-            return 0;
-        }
-
-        StackBase = Frame;
-        StackEnd = (PULONG)((ULONG_PTR)mbi.BaseAddress + mbi.RegionSize);
-
-        while ( Count < FrameCount && Frame >= StackBase && Frame < StackEnd )
-        {
-            Frames[Count++] = Frame[1];
-            StackBase = Frame;
-            Frame = (PULONG)Frame[0];
-        }
-    }
-    _SEH_HANDLE
-    {
-    }
-    _SEH_END;
-    return Count;
-}
-
-VOID
-NTAPI
-KeDumpStackFrames(PULONG Frame)
-{
-    /* Just call the extended version */
-    KeRosDumpStackFrames(Frame, 0);
-}
-
 VOID
 NTAPI
 KeRosDumpStackFrames(IN PULONG Frame OPTIONAL,
                      IN ULONG FrameCount OPTIONAL)
 {
     ULONG Frames[32];
-    ULONG Count, i, Addr;
-
-    /* Don't let anyone ask more then 32 frames */
-    if (FrameCount > 32) return;
+    ULONG i, Addr;
 
     /* If the caller didn't ask, assume 32 frames */
     if (!FrameCount) FrameCount = 32;
 
-    /* Get the current frames, and make sure caller didn't ask too many */
-    Count = KeRosGetStackFrames(Frames, FrameCount); // <= should be replaced with Rtl
-    if (FrameCount > Count) FrameCount = Count;
+    /* Get the current frames */
+    FrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL);
 
     /* Now loop them (skip the two. One for the dumper, one for the caller) */
-    for (i = 2; i < FrameCount; i++)
+    for (i = 0; i < FrameCount; i++)
     {
         /* Get the EIP */
         Addr = Frames[i];
@@ -178,9 +101,6 @@ KeRosDumpStackFrames(IN PULONG Frame OPTIONAL,
         /* Print it out */
         if (!KeRosPrintAddress((PVOID)Addr)) DbgPrint("<%X>", Addr);
 
-        /* Break out of invalid addresses */
-        if (Addr == 0 || Addr == 0xDEADBEEF) break;
-
         /* Go to the next frame */
         DbgPrint("\n");
     }
@@ -198,10 +118,12 @@ KiInitializeBugCheck(VOID)
     LDR_RESOURCE_INFO ResourceInfo;
     PIMAGE_RESOURCE_DATA_ENTRY ResourceDataEntry;
     NTSTATUS Status;
+    PLDR_DATA_TABLE_ENTRY LdrEntry;
 
-    /* Initialize Callbadk Listhead and State */
-    InitializeListHead(&BugcheckCallbackListHead);
-    InitializeListHead(&BugcheckReasonCallbackListHead);
+    /* 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;
@@ -209,7 +131,7 @@ KiInitializeBugCheck(VOID)
     ResourceInfo.Language = 9;
 
     /* Do the lookup. */
-    Status = LdrFindResource_U((PVOID)KERNEL_BASE,
+    Status = LdrFindResource_U(LdrEntry->DllBase,
                                &ResourceInfo,
                                RESOURCE_DATA_LEVEL,
                                &ResourceDataEntry);
@@ -218,7 +140,7 @@ KiInitializeBugCheck(VOID)
     if (NT_SUCCESS(Status))
     {
         /* Now actually get a pointer to it */
-        Status = LdrAccessResource((PVOID)KERNEL_BASE,
+        Status = LdrAccessResource(LdrEntry->DllBase,
                                    ResourceDataEntry,
                                    (PVOID*)&BugCheckData,
                                    NULL);
@@ -267,7 +189,7 @@ KeGetBugMessageText(IN ULONG BugCheckCode,
                 OutputString->Length = i + 1;
                 OutputString->MaximumLength = i + 1;
             }
-            else 
+            else
             {
                 /* Direct Output to Screen */
                 InbvDisplayString(BugCode);
@@ -287,7 +209,7 @@ KiDoBugCheckCallbacks(VOID)
     ULONG_PTR Checksum;
 
     /* First make sure that the list is Initialized... it might not be */
-    ListHead = &BugcheckCallbackListHead;
+    ListHead = &KeBugcheckCallbackListHead;
     if ((ListHead->Flink) && (ListHead->Blink))
     {
         /* Loop the list */
@@ -345,13 +267,13 @@ KiPcToFileHeader(IN PVOID Eip,
     PVOID ImageBase, EipBase = NULL;
     PLDR_DATA_TABLE_ENTRY Entry;
     PLIST_ENTRY ListHead, NextEntry;
-    extern LIST_ENTRY ModuleListHead;
+    extern LIST_ENTRY PsLoadedModuleList;
 
     /* Assume no */
     *InKernel = FALSE;
 
     /* Set list pointers and make sure it's valid */
-    ListHead = &ModuleListHead;
+    ListHead = &PsLoadedModuleList;
     NextEntry = ListHead->Flink;
     if (NextEntry)
     {
@@ -505,7 +427,20 @@ KiDisplayBlueScreen(IN ULONG MessageId,
 {
     CHAR AnsiName[75];
 
-    /* FIXMEs: Use inbv to clear, fill and write to screen. */
+    /* 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)
@@ -513,7 +448,6 @@ KiDisplayBlueScreen(IN ULONG MessageId,
         /* Display caption and message */
         if (HardErrCaption) InbvDisplayString(HardErrCaption);
         if (HardErrMessage) InbvDisplayString(HardErrMessage);
-        return;
     }
 
     /* Begin the display */
@@ -594,13 +528,16 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
     CONTEXT Context;
     ULONG MessageId;
     CHAR AnsiName[128];
-    BOOLEAN IsSystem, IsHardError = FALSE;
+    BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE;
     PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
     PVOID Eip = NULL, Memory;
     PVOID DriverBase;
     PLDR_DATA_TABLE_ENTRY LdrEntry;
     PULONG_PTR HardErrorParameters;
     KIRQL OldIrql;
+#ifdef CONFIG_SMP
+    LONG i = 0;
+#endif
 
     /* Set active bugcheck */
     KeBugCheckActive = TRUE;
@@ -616,13 +553,14 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
 
     /* Save the IRQL and set hardware trigger */
     Prcb->DebuggerSavedIRQL = KeGetCurrentIrql();
-    InterlockedIncrement(&KiHardwareTrigger);
+    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 regsitered */
+    /* FIXME: Call the Watchdog if it's registered */
 
     /* Check which bugcode this is */
     switch (BugCheckCode)
@@ -637,7 +575,6 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
         case FAT_FILE_SYSTEM:
         case NO_MORE_SYSTEM_PTES:
         case INACCESSIBLE_BOOT_DEVICE:
-        case KMODE_EXCEPTION_NOT_HANDLED:
 
             /* Keep the same code */
             MessageId = BugCheckCode;
@@ -645,33 +582,40 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
 
         /* 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 */
@@ -798,9 +742,13 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
             {
                 /* Get EIP */
                 Eip = (PVOID)TrapFrame->Eip;
+                KiBugCheckData[3] = (ULONG)Eip;
 
                 /* Find out if was in the kernel or drivers */
-                DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
+                DriverBase = KiPcToFileHeader(Eip,
+                                              &LdrEntry,
+                                              FALSE,
+                                              &IsSystem);
             }
 
             /*
@@ -809,8 +757,8 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
              * and update the bugcheck code appropriately.
              */
 
-            /* Check if we had a driver base */
-            if (DriverBase)
+            /* 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
@@ -834,8 +782,8 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
         /* Check if the driver consumed too many PTEs */
         case DRIVER_USED_EXCESSIVE_PTES:
 
-            /* Driver base is in parameter 1 */
-            DriverBase = (PVOID)BugCheckParameter1;
+            /* Loader entry is in parameter 1 */
+            LdrEntry = (PVOID)BugCheckParameter1;
             KiBugCheckDriver = &LdrEntry->BaseDllName;
             break;
 
@@ -870,7 +818,7 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
         }
     }
 
-    /* FIXME: Check if we need to save the context for KD */
+    /* Check if we need to save the context for KD */
 
     /* Check if a debugger is connected */
     if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
@@ -916,28 +864,25 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
         }
     }
 
-    /* Switching back to the blue screen so we print messages on it */
-    HalReleaseDisplayOwnership();
-
     /* Raise IRQL to HIGH_LEVEL */
-    Ke386DisableInterrupts();
+    _disable();
     KeRaiseIrql(HIGH_LEVEL, &OldIrql);
 
-    /* Unlock the Kernel Adress Space if we own it */
+    /* ROS HACK: Unlock the Kernel Address Space if we own it */
     if (KernelAddressSpaceLock.Owner == KeGetCurrentThread())
     {
         MmUnlockAddressSpace(MmGetKernelAddressSpace());
     }
 
     /* Avoid recursion */
-    if (!InterlockedDecrement(&KeBugCheckCount))
+    if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
     {
+#ifdef CONFIG_SMP
         /* Set CPU that is bug checking now */
         KeBugCheckOwner = Prcb->Number;
 
-#ifdef CONFIG_SMP
         /* Freeze the other CPUs */
-        for (i = 0; i < KeNumberProcessors; i++) 
+        for (i = 0; i < KeNumberProcessors; i++)
         {
             if (i != (LONG)KeGetCurrentProcessorNumber())
             {
@@ -955,10 +900,17 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
                             HardErrMessage,
                             AnsiName);
 
-        /* FIXME: Enable debugger if it was pending */
-
-        /* Print the last line */
-        InbvDisplayString("\r\n");
+        /* Check if the debugger is disabled but we can enable it */
+        //if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
+        {
+            /* Enable it */
+            //KdEnableDebuggerWithLock(FALSE);
+        }
+        //else
+        {
+            /* Otherwise, print the last line */
+            InbvDisplayString("\r\n");
+        }
 
         /* Save the context */
         Prcb->ProcessorState.ContextFrame = Context;
@@ -973,18 +925,20 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
                            KiBugCheckData[3],
                            TrapFrame);
     }
-
-    /* Increase recursioun count */
-    KeBugCheckOwnerRecursionCount++;
-    if (KeBugCheckOwnerRecursionCount == 2)
-    {
-        /* Break in the debugger */
-        KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
-    }
-    else if (KeBugCheckOwnerRecursionCount > 2)
+    else
     {
-        /* Halt the CPU */
-        for (;;) Ke386HaltProcessor();
+        /* Increase recursion count */
+        KeBugCheckOwnerRecursionCount++;
+        if (KeBugCheckOwnerRecursionCount == 2)
+        {
+            /* Break in the debugger */
+            KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
+        }
+        else if (KeBugCheckOwnerRecursionCount > 2)
+        {
+            /* Halt the CPU */
+            for (;;) Ke386HaltProcessor();
+        }
     }
 
     /* Call the Callbacks */
@@ -992,6 +946,14 @@ KeBugCheckWithTf(IN ULONG BugCheckCode,
 
     /* FIXME: Call Watchdog if enabled */
 
+    /* Check if we have to reboot */
+    if (Reboot)
+    {
+        /* Unload symbols */
+        DbgUnLoadImageSymbols(NULL, NtCurrentProcess(), 0);
+        HalReturnToFirmware(HalRebootRoutine);
+    }
+
     /* Attempt to break in the debugger (otherwise halt CPU) */
     KiBugCheckDebugBreak(DBG_STATUS_BUGCHECK_SECOND);
 }
@@ -1079,7 +1041,7 @@ KeRegisterBugCheckCallback(IN PKBUGCHECK_CALLBACK_RECORD CallbackRecord,
         CallbackRecord->Component = Component;
         CallbackRecord->CallbackRoutine = CallbackRoutine;
         CallbackRecord->State = BufferInserted;
-        InsertTailList(&BugcheckCallbackListHead, &CallbackRecord->Entry);
+        InsertTailList(&KeBugcheckCallbackListHead, &CallbackRecord->Entry);
         Status = TRUE;
     }
 
@@ -1113,7 +1075,7 @@ KeRegisterBugCheckReasonCallback(
         CallbackRecord->CallbackRoutine = CallbackRoutine;
         CallbackRecord->State = BufferInserted;
         CallbackRecord->Reason = Reason;
-        InsertTailList(&BugcheckReasonCallbackListHead,
+        InsertTailList(&KeBugcheckReasonCallbackListHead,
                        &CallbackRecord->Entry);
         Status = TRUE;
     }