#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, KiInitializeBugCheck)
PUNICODE_STRING KiBugCheckDriver;
ULONG_PTR KiBugCheckData[5];
+/* Bugzilla Reporting */
+UNICODE_STRING KeRosProcessorName, KeRosBiosDate, KeRosBiosVersion;
+UNICODE_STRING KeRosVideoBiosDate, KeRosVideoBiosVersion;
+
/* PRIVATE FUNCTIONS *********************************************************/
+PVOID
+NTAPI
+KiPcToFileHeader(IN PVOID Pc,
+ OUT PLDR_DATA_TABLE_ENTRY *LdrEntry,
+ IN BOOLEAN DriversOnly,
+ OUT PBOOLEAN InKernel)
+{
+ ULONG i = 0;
+ PVOID ImageBase, PcBase = NULL;
+ PLDR_DATA_TABLE_ENTRY Entry;
+ PLIST_ENTRY ListHead, NextEntry;
+
+ /* Check which list we should use */
+ ListHead = (KeLoaderBlock) ? &KeLoaderBlock->LoadOrderListHead :
+ &PsLoadedModuleList;
+
+ /* Assume no */
+ *InKernel = FALSE;
+
+ /* Set list pointers and make sure it's valid */
+ NextEntry = ListHead->Flink;
+ if (NextEntry)
+ {
+ /* Start loop */
+ while (NextEntry != ListHead)
+ {
+ /* Increase entry */
+ i++;
+
+ /* Check if this is a kernel entry and we only want drivers */
+ if ((i <= 2) && (DriversOnly == TRUE))
+ {
+ /* Skip it */
+ NextEntry = NextEntry->Flink;
+ continue;
+ }
+
+ /* 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;
+
+ /* Check if this was a kernel or HAL entry */
+ if (i <= 2) *InKernel = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* Return the base address */
+ return PcBase;
+}
+
BOOLEAN
NTAPI
KiRosPrintAddress(PVOID address)
return(FALSE);
}
-VOID
+PVOID
NTAPI
-KeRosDumpStackFrames(IN PULONG Frame OPTIONAL,
- IN ULONG FrameCount OPTIONAL)
+KiRosPcToUserFileHeader(IN PVOID Pc,
+ OUT PLDR_DATA_TABLE_ENTRY *LdrEntry)
{
- ULONG Frames[32];
- ULONG i, Addr;
+ PVOID ImageBase, PcBase = NULL;
+ PLDR_DATA_TABLE_ENTRY Entry;
+ PLIST_ENTRY ListHead, NextEntry;
- /* If the caller didn't ask, assume 32 frames */
- if (!FrameCount) FrameCount = 32;
+ /*
+ * 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;
- /* Get the current frames */
- FrameCount = RtlCaptureStackBackTrace(2, FrameCount, (PVOID*)Frames, NULL);
+ /* 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;
+ }
+ }
+ }
+
+ /* Return the base address */
+ return PcBase;
+}
+
+USHORT
+NTAPI
+KeRosCaptureUserStackBackTrace(IN ULONG FramesToSkip,
+ IN ULONG FramesToCapture,
+ OUT PVOID *BackTrace,
+ OUT PULONG BackTraceHash OPTIONAL)
+{
+ PVOID Frames[2 * 64];
+ ULONG FrameCount;
+ ULONG Hash = 0, i;
+
+ /* Skip a frame for the caller */
+ FramesToSkip++;
+
+ /* Don't go past the limit */
+ if ((FramesToCapture + FramesToSkip) >= 128) return 0;
+
+ /* Do the back trace */
+ FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 1);
+
+ /* 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]);
+ }
+
+ /* Write the hash */
+ if (BackTraceHash) *BackTraceHash = Hash;
+
+ /* Clear the other entries and return count */
+ RtlFillMemoryUlong(Frames, 128, 0);
+ return (USHORT)i;
+}
+
+VOID
+FASTCALL
+KeRosDumpStackFrameArray(IN PULONG_PTR Frames,
+ IN ULONG FrameCount)
+{
+ ULONG i;
+ ULONG_PTR Addr;
+ BOOLEAN InSystem;
+ PVOID p;
- /* Now loop them (skip the two. One for the dumper, one for the caller) */
+ /* GCC complaints that it may be used uninitialized */
+ PLDR_DATA_TABLE_ENTRY LdrEntry = NULL;
+
+ /* Loop them */
for (i = 0; i < FrameCount; i++)
{
/* Get the EIP */
Addr = Frames[i];
+ if (!Addr)
+ {
+ break;
+ }
- /* If we had a custom frame, make sure we've reached it first */
- if ((Frame) && (Frame[1] == Addr))
+ /* Get the base for this file */
+ if (Addr > (ULONG_PTR)MmHighestUserAddress)
{
- Frame = NULL;
+ /* We are in kernel */
+ p = KiPcToFileHeader((PVOID)Addr, &LdrEntry, FALSE, &InSystem);
}
- else if (Frame)
+ else
{
- /* Skip this entry */
- continue;
+ /* 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);
}
-
- /* Print it out */
- if (!KiRosPrintAddress((PVOID)Addr)) DbgPrint("<%X>", Addr);
/* Go to the next frame */
DbgPrint("\n");
}
+}
+
+VOID
+NTAPI
+KeRosDumpStackFrames(IN PULONG_PTR Frame OPTIONAL,
+ IN ULONG FrameCount OPTIONAL)
+{
+ ULONG_PTR Frames[32];
+ ULONG RealFrameCount;
+
+ /* If the caller didn't ask, assume 32 frames */
+ if (!FrameCount || FrameCount > 32) FrameCount = 32;
+
+ 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);
- /* Finish the output */
- DbgPrint("\n");
+ /* Dump them */
+ KeRosDumpStackFrameArray(Frames, RealFrameCount);
+
+ /* 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);
+ }
+ }
+}
+
+
+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
}
}
-VOID
+BOOLEAN
NTAPI
KeGetBugMessageText(IN ULONG BugCheckCode,
OUT PANSI_STRING OutputString OPTIONAL)
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 */
for (i = 0; i < KiBugCodeMessages->NumberOfBlocks; i++)
/* Check if the ID Matches */
if ((BugCheckCode >= KiBugCodeMessages->Blocks[i].LowId) &&
(BugCheckCode <= KiBugCodeMessages->Blocks[i].HighId))
- {
+ {
/* Get Offset to Entry */
MessageEntry = KiBugCodeMessages->Blocks[i].OffsetToEntries +
(ULONG_PTR)KiBugCodeMessages;
BugCode = ((PRTL_MESSAGE_RESOURCE_ENTRY)MessageEntry)->Text;
i = strlen(BugCode);
- /* Return it in the OutputString */
+ /* 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--;
+ }
+
+ /* Check if caller wants an output string */
if (OutputString)
{
+ /* Return it in the OutputString */
OutputString->Buffer = BugCode;
- OutputString->Length = i + 1;
- OutputString->MaximumLength = i + 1;
+ OutputString->Length = (USHORT)i + 1;
+ OutputString->MaximumLength = (USHORT)i + 1;
}
else
{
/* Direct Output to Screen */
InbvDisplayString(BugCode);
InbvDisplayString("\r");
- break;
}
+
+ /* We're done */
+ Result = TRUE;
+ break;
}
}
+
+ /* Return the result */
+ return Result;
}
VOID
NTAPI
KiBugCheckDebugBreak(IN ULONG StatusCode)
{
- /* If KDBG isn't connected, freeze the CPU, otherwise, break */
- if (KdDebuggerNotPresent) for (;;) Ke386HaltProcessor();
- DbgBreakPointWithStatus(StatusCode);
-}
-
-PVOID
-NTAPI
-KiPcToFileHeader(IN PVOID Eip,
- OUT PLDR_DATA_TABLE_ENTRY *LdrEntry,
- IN BOOLEAN DriversOnly,
- OUT PBOOLEAN InKernel)
-{
- ULONG i = 0;
- PVOID ImageBase, EipBase = NULL;
- PLDR_DATA_TABLE_ENTRY Entry;
- PLIST_ENTRY ListHead, NextEntry;
- extern LIST_ENTRY PsLoadedModuleList;
-
- /* Assume no */
- *InKernel = FALSE;
-
- /* Set list pointers and make sure it's valid */
- ListHead = &PsLoadedModuleList;
- NextEntry = ListHead->Flink;
- if (NextEntry)
+ /*
+ * Wrap this in SEH so we don't crash if
+ * there is no debugger or if it disconnected
+ */
+DoBreak:
+ _SEH2_TRY
{
- /* Start loop */
- while (NextEntry != ListHead)
- {
- /* Increase entry */
- i++;
-
- /* Check if this is a kernel entry and we only want drivers */
- if ((i <= 2) && (DriversOnly == TRUE))
- {
- /* Skip it */
- NextEntry = NextEntry->Flink;
- continue;
- }
-
- /* 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)Eip >= (ULONG_PTR)Entry->DllBase) &&
- ((ULONG_PTR)Eip < ((ULONG_PTR)Entry->DllBase + Entry->SizeOfImage)))
- {
- /* Return this entry */
- *LdrEntry = Entry;
- EipBase = ImageBase;
-
- /* Check if this was a kernel or HAL entry */
- if (i <= 2) *InKernel = TRUE;
- break;
- }
- }
+ /* Breakpoint */
+ DbgBreakPointWithStatus(StatusCode);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* No debugger, halt the CPU */
+ HalHaltSystem();
}
+ _SEH2_END;
- /* Return the base address */
- return EipBase;
+ /* Break again if this wasn't first try */
+ if (StatusCode != DBG_STATUS_BUGCHECK_FIRST) goto DoBreak;
}
PCHAR
&InSystem);
if (!ImageBase)
{
- /* Driver wasn't found, check for unloaded driver */
- DriverName = NULL; // FIXME: ROS can't
- if (!DriverName) continue;
-
- /* Convert the driver name */
- ImageBase = (PVOID)Parameters[i];
- ConversionRoutine(DriverName, AnsiName, sizeof(AnsiName));
+ /* FIXME: Add code to check for unloaded drivers */
+ DPRINT1("Potentially unloaded driver!\n");
+ continue;
}
else
{
/* Print message for technical information */
KeGetBugMessageText(BUGCHECK_TECH_INFO, NULL);
- /* Show the techincal Data */
+ /* Show the technical Data */
sprintf(AnsiName,
- "\r\n\r\n*** STOP: 0x%08lX (0x%p,0x%p,0x%p,0x%p)\r\n\r\n",
- KiBugCheckData[0],
+ "\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],
CHAR AnsiName[128];
BOOLEAN IsSystem, IsHardError = FALSE, Reboot = FALSE;
PCHAR HardErrCaption = NULL, HardErrMessage = NULL;
- PVOID Eip = NULL, Memory;
+ PVOID Pc = NULL, Memory;
PVOID DriverBase;
PLDR_DATA_TABLE_ENTRY LdrEntry;
PULONG_PTR HardErrorParameters;
if (BugCheckParameter3) TrapFrame = (PVOID)BugCheckParameter3;
}
- /* Check if we got one now and if we need to get EIP */
+ /* Check if we got one now and if we need to get the Program Counter */
if ((TrapFrame) &&
(BugCheckCode != KERNEL_MODE_EXCEPTION_NOT_HANDLED))
{
- /* Get EIP */
- Eip = (PVOID)TrapFrame->Eip;
+ /* Get the Program Counter */
+ Pc = (PVOID)KeGetTrapFramePc(TrapFrame);
}
break;
* and provide a more detailed analysis. For now, we don't.
*/
- /* Eip is in parameter 4 */
- Eip = (PVOID)BugCheckParameter4;
+ /* Program Counter is in parameter 4 */
+ Pc = (PVOID)BugCheckParameter4;
/* Get the driver base */
- DriverBase = KiPcToFileHeader(Eip, &LdrEntry, FALSE, &IsSystem);
+ DriverBase = KiPcToFileHeader(Pc,
+ &LdrEntry,
+ FALSE,
+ &IsSystem);
if (IsSystem)
{
/*
KiBugCheckData[0] = DRIVER_IRQL_NOT_LESS_OR_EQUAL;
}
- /* Clear EIP so we don't look it up later */
- Eip = NULL;
+ /* Clear Pc so we don't look it up later */
+ Pc = NULL;
break;
/* Hard error */
/* Check if we have a frame now */
if (TrapFrame)
{
- /* Get EIP */
- Eip = (PVOID)TrapFrame->Eip;
- KiBugCheckData[3] = (ULONG)Eip;
+ /* Get the Program Counter */
+ Pc = (PVOID)KeGetTrapFramePc(TrapFrame);
+ KiBugCheckData[3] = (ULONG_PTR)Pc;
/* Find out if was in the kernel or drivers */
- DriverBase = KiPcToFileHeader(Eip,
+ DriverBase = KiPcToFileHeader(Pc,
&LdrEntry,
FALSE,
&IsSystem);
/* Check if the driver forgot to unlock pages */
case DRIVER_LEFT_LOCKED_PAGES_IN_PROCESS:
- /* EIP is in parameter 1 */
- Eip = (PVOID)BugCheckParameter1;
+ /* Program Counter is in parameter 1 */
+ Pc = (PVOID)BugCheckParameter1;
break;
/* Check if the driver consumed too many PTEs */
}
else
{
- /* Do we have an EIP? */
- if (Eip)
+ /* Do we have a Program Counter? */
+ if (Pc)
{
/* Dump image name */
KiDumpParameterImages(AnsiName,
- (PULONG_PTR)&Eip,
+ (PULONG_PTR)&Pc,
1,
KeBugCheckUnicodeToAnsi);
}
}
/* Check if we need to save the context for KD */
- if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG)&Context;
+#ifdef _WINKD_
+ if (!KdPitchDebugger) KdDebuggerDataBlock.SavedContext = (ULONG_PTR)&Context;
+#endif
/* Check if a debugger is connected */
if ((BugCheckCode != MANUALLY_INITIATED_CRASH) && (KdDebuggerEnabled))
/* 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();
+ }
}
/* Raise IRQL to HIGH_LEVEL */
_disable();
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
- /* ROS HACK: Unlock the Kernel Address Space if we own it */
- if (KernelAddressSpaceLock.Owner == KeGetCurrentThread())
- {
- MmUnlockAddressSpace(MmGetKernelAddressSpace());
- }
-
/* Avoid recursion */
if (!InterlockedDecrement((PLONG)&KeBugCheckCount))
{
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);
}
}
if (!(KdDebuggerEnabled) && !(KdPitchDebugger))
{
/* Enable it */
+#ifdef _WINKD_
KdEnableDebuggerWithLock(FALSE);
+#endif
}
else
{
/* FIXME: Support Triage Dump */
- /* Write the crash dump */
- MmDumpToPagingFile(KiBugCheckData[4],
- KiBugCheckData[0],
- KiBugCheckData[1],
- KiBugCheckData[2],
- KiBugCheckData[3],
- TrapFrame);
+ /* FIXME: Write the crash dump */
}
else
{
}
else if (KeBugCheckOwnerRecursionCount > 2)
{
- /* Halt the CPU */
- for (;;) Ke386HaltProcessor();
+ /* Halt execution */
+ while (TRUE);
}
}
if (Reboot)
{
/* Unload symbols */
- DbgUnLoadImageSymbols(NULL, NtCurrentProcess(), 0);
+ 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
*/
return Status;
}
+/*
+ * @unimplemented
+ */
+NTSTATUS
+NTAPI
+KeDeregisterNmiCallback(PVOID Handle)
+{
+ UNIMPLEMENTED;
+ return STATUS_UNSUCCESSFUL;
+}
+
/*
* @implemented
*/
return Status;
}
+/*
+ * @unimplemented
+ */
+PVOID
+NTAPI
+KeRegisterNmiCallback(IN PNMI_CALLBACK CallbackRoutine,
+ IN PVOID Context)
+{
+ UNIMPLEMENTED;
+ return NULL;
+}
+
/*
* @implemented
*/
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 */