/*
- * 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>", ¤t->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,
/*
* @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 */