mirror of
https://github.com/reactos/reactos.git
synced 2024-08-18 17:37:02 +00:00
381 lines
10 KiB
C
381 lines
10 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: ntoskrnl/kd/kdio.c
|
|
* PURPOSE: NT Kernel Debugger Input/Output Functions
|
|
*
|
|
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
#define KdpBufferSize (1024 * 512)
|
|
BOOLEAN KdpLoggingEnabled = FALSE;
|
|
PCHAR KdpDebugBuffer = NULL;
|
|
volatile ULONG KdpCurrentPosition = 0;
|
|
volatile ULONG KdpFreeBytes = 0;
|
|
KSPIN_LOCK KdpDebugLogSpinLock;
|
|
KEVENT KdpLoggerThreadEvent;
|
|
HANDLE KdpLogFileHandle;
|
|
|
|
KSPIN_LOCK KdpSerialSpinLock;
|
|
KD_PORT_INFORMATION SerialPortInfo = { DEFAULT_DEBUG_PORT, DEFAULT_DEBUG_BAUD_RATE, 0 };
|
|
|
|
/* Current Port in use. FIXME: Do we support more then one? */
|
|
ULONG KdpPort;
|
|
|
|
/* DEBUG LOG FUNCTIONS *******************************************************/
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpLoggerThread(PVOID Context)
|
|
{
|
|
ULONG beg, end, num;
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
KdpLoggingEnabled = TRUE;
|
|
|
|
while (TRUE)
|
|
{
|
|
KeWaitForSingleObject(&KdpLoggerThreadEvent, 0, KernelMode, FALSE, NULL);
|
|
|
|
/* Bug */
|
|
end = KdpCurrentPosition;
|
|
num = KdpFreeBytes;
|
|
beg = (end + num) % KdpBufferSize;
|
|
num = KdpBufferSize - num;
|
|
|
|
/* Nothing to do? */
|
|
if (num == 0)
|
|
continue;
|
|
|
|
if (end > beg)
|
|
{
|
|
NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
|
|
KdpDebugBuffer + beg, num, NULL, NULL);
|
|
}
|
|
else
|
|
{
|
|
NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
|
|
KdpDebugBuffer + beg, KdpBufferSize - beg, NULL, NULL);
|
|
|
|
NtWriteFile(KdpLogFileHandle, NULL, NULL, NULL, &Iosb,
|
|
KdpDebugBuffer, end, NULL, NULL);
|
|
}
|
|
|
|
(VOID)InterlockedExchangeAddUL(&KdpFreeBytes, num);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpPrintToLogFile(PCH String,
|
|
ULONG StringLength)
|
|
{
|
|
ULONG beg, end, num;
|
|
KIRQL OldIrql;
|
|
|
|
if (KdpDebugBuffer == NULL) return;
|
|
|
|
/* Acquire the printing spinlock without waiting at raised IRQL */
|
|
while (TRUE)
|
|
{
|
|
/* Wait when the spinlock becomes available */
|
|
while (!KeTestSpinLock(&KdpDebugLogSpinLock));
|
|
|
|
/* Spinlock was free, raise IRQL */
|
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|
|
|
/* Try to get the spinlock */
|
|
if (KeTryToAcquireSpinLockAtDpcLevel(&KdpDebugLogSpinLock))
|
|
break;
|
|
|
|
/* Someone else got the spinlock, lower IRQL back */
|
|
KeLowerIrql(OldIrql);
|
|
}
|
|
|
|
beg = KdpCurrentPosition;
|
|
num = KdpFreeBytes;
|
|
if (StringLength < num)
|
|
num = StringLength;
|
|
|
|
if (num != 0)
|
|
{
|
|
end = (beg + num) % KdpBufferSize;
|
|
KdpCurrentPosition = end;
|
|
KdpFreeBytes -= num;
|
|
|
|
if (end > beg)
|
|
{
|
|
RtlCopyMemory(KdpDebugBuffer + beg, String, num);
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory(KdpDebugBuffer + beg, String, KdpBufferSize - beg);
|
|
RtlCopyMemory(KdpDebugBuffer, String + KdpBufferSize - beg, end);
|
|
}
|
|
}
|
|
|
|
/* Release spinlock */
|
|
KiReleaseSpinLock(&KdpDebugLogSpinLock);
|
|
|
|
/* Lower IRQL */
|
|
KeLowerIrql(OldIrql);
|
|
|
|
/* Signal the logger thread */
|
|
if (OldIrql <= DISPATCH_LEVEL && KdpLoggingEnabled)
|
|
KeSetEvent(&KdpLoggerThreadEvent, 0, FALSE);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpInitDebugLog(PKD_DISPATCH_TABLE DispatchTable,
|
|
ULONG BootPhase)
|
|
{
|
|
NTSTATUS Status;
|
|
UNICODE_STRING FileName;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
IO_STATUS_BLOCK Iosb;
|
|
HANDLE ThreadHandle;
|
|
KPRIORITY Priority;
|
|
|
|
if (!KdpDebugMode.File) return;
|
|
|
|
if (BootPhase == 0)
|
|
{
|
|
KdComPortInUse = NULL;
|
|
|
|
/* Write out the functions that we support for now */
|
|
DispatchTable->KdpInitRoutine = KdpInitDebugLog;
|
|
DispatchTable->KdpPrintRoutine = KdpPrintToLogFile;
|
|
|
|
/* Register as a Provider */
|
|
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
|
|
|
|
}
|
|
else if (BootPhase == 1)
|
|
{
|
|
/* Allocate a buffer for debug log */
|
|
KdpDebugBuffer = ExAllocatePool(NonPagedPool, KdpBufferSize);
|
|
KdpFreeBytes = KdpBufferSize;
|
|
|
|
/* Initialize spinlock */
|
|
KeInitializeSpinLock(&KdpDebugLogSpinLock);
|
|
|
|
/* Display separator + ReactOS version at start of the debug log */
|
|
DPRINT1("---------------------------------------------------------------\n");
|
|
DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n");
|
|
}
|
|
else if (BootPhase == 2)
|
|
{
|
|
HalDisplayString("\n File log debugging enabled\n\n");
|
|
}
|
|
else if (BootPhase == 3)
|
|
{
|
|
/* Setup the log name */
|
|
RtlInitUnicodeString(&FileName, L"\\SystemRoot\\debug.log");
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&FileName,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
/* Create the log file */
|
|
Status = NtCreateFile(&KdpLogFileHandle,
|
|
FILE_APPEND_DATA | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&Iosb,
|
|
NULL,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ,
|
|
FILE_SUPERSEDE,
|
|
FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
|
|
NULL,
|
|
0);
|
|
|
|
if (!NT_SUCCESS(Status)) return;
|
|
|
|
KeInitializeEvent(&KdpLoggerThreadEvent, SynchronizationEvent, TRUE);
|
|
|
|
/* Create the logger thread */
|
|
Status = PsCreateSystemThread(&ThreadHandle,
|
|
THREAD_ALL_ACCESS,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
KdpLoggerThread,
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) return;
|
|
|
|
Priority = 7;
|
|
NtSetInformationThread(ThreadHandle,
|
|
ThreadPriority,
|
|
&Priority,
|
|
sizeof(Priority));
|
|
}
|
|
}
|
|
|
|
/* SERIAL FUNCTIONS **********************************************************/
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpSerialDebugPrint(LPSTR Message,
|
|
ULONG Length)
|
|
{
|
|
KIRQL OldIrql;
|
|
PCHAR pch = (PCHAR) Message;
|
|
|
|
/* Acquire the printing spinlock without waiting at raised IRQL */
|
|
while (TRUE)
|
|
{
|
|
/* Wait when the spinlock becomes available */
|
|
while (!KeTestSpinLock(&KdpSerialSpinLock));
|
|
|
|
/* Spinlock was free, raise IRQL */
|
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|
|
|
/* Try to get the spinlock */
|
|
if (KeTryToAcquireSpinLockAtDpcLevel(&KdpSerialSpinLock))
|
|
break;
|
|
|
|
/* Someone else got the spinlock, lower IRQL back */
|
|
KeLowerIrql(OldIrql);
|
|
}
|
|
|
|
/* Output the message */
|
|
while (*pch != 0)
|
|
{
|
|
if (*pch == '\n')
|
|
{
|
|
KdPortPutByteEx(&SerialPortInfo, '\r');
|
|
}
|
|
KdPortPutByteEx(&SerialPortInfo, *pch);
|
|
pch++;
|
|
}
|
|
|
|
/* Release spinlock */
|
|
KiReleaseSpinLock(&KdpSerialSpinLock);
|
|
|
|
/* Lower IRQL */
|
|
KeLowerIrql(OldIrql);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpSerialInit(PKD_DISPATCH_TABLE DispatchTable,
|
|
ULONG BootPhase)
|
|
{
|
|
if (!KdpDebugMode.Serial) return;
|
|
|
|
if (BootPhase == 0)
|
|
{
|
|
/* Write out the functions that we support for now */
|
|
DispatchTable->KdpInitRoutine = KdpSerialInit;
|
|
DispatchTable->KdpPrintRoutine = KdpSerialDebugPrint;
|
|
|
|
/* Initialize the Port */
|
|
if (!KdPortInitializeEx(&SerialPortInfo, 0, 0))
|
|
{
|
|
KdpDebugMode.Serial = FALSE;
|
|
return;
|
|
}
|
|
KdComPortInUse = (PUCHAR)(ULONG_PTR)SerialPortInfo.BaseAddress;
|
|
|
|
/* Initialize spinlock */
|
|
KeInitializeSpinLock(&KdpSerialSpinLock);
|
|
|
|
/* Register as a Provider */
|
|
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
|
|
|
|
/* Display separator + ReactOS version at start of the debug log */
|
|
DPRINT1("-----------------------------------------------------\n");
|
|
DPRINT1("ReactOS "KERNEL_VERSION_STR" (Build "KERNEL_VERSION_BUILD_STR")\n");
|
|
DPRINT1("Command Line: %s\n", KeLoaderBlock->LoadOptions);
|
|
DPRINT1("ARC Paths: %s %s %s %s\n", KeLoaderBlock->ArcBootDeviceName,
|
|
KeLoaderBlock->NtHalPathName,
|
|
KeLoaderBlock->ArcHalDeviceName,
|
|
KeLoaderBlock->NtBootPathName);
|
|
}
|
|
else if (BootPhase == 2)
|
|
{
|
|
HalDisplayString("\n Serial debugging enabled\n\n");
|
|
}
|
|
}
|
|
|
|
/* SCREEN FUNCTIONS **********************************************************/
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpScreenPrint(LPSTR Message,
|
|
ULONG Length)
|
|
{
|
|
/* Call HAL */
|
|
HalDisplayString(Message);
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable,
|
|
ULONG BootPhase)
|
|
{
|
|
if (!KdpDebugMode.Screen) return;
|
|
|
|
if (BootPhase == 0)
|
|
{
|
|
/* Write out the functions that we support for now */
|
|
DispatchTable->KdpInitRoutine = KdpScreenInit;
|
|
DispatchTable->KdpPrintRoutine = KdpScreenPrint;
|
|
|
|
/* Register as a Provider */
|
|
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
|
|
}
|
|
else if (BootPhase == 2)
|
|
{
|
|
HalDisplayString("\n Screen debugging enabled\n\n");
|
|
}
|
|
}
|
|
|
|
/* GENERAL FUNCTIONS *********************************************************/
|
|
|
|
ULONG
|
|
NTAPI
|
|
KdpPrintString(LPSTR String,
|
|
ULONG Length)
|
|
{
|
|
PLIST_ENTRY CurrentEntry;
|
|
PKD_DISPATCH_TABLE CurrentTable;
|
|
|
|
if (!KdpDebugMode.Value) return 0;
|
|
|
|
/* Call the registered handlers */
|
|
CurrentEntry = KdProviders.Flink;
|
|
while (CurrentEntry != &KdProviders)
|
|
{
|
|
/* Get the current table */
|
|
CurrentTable = CONTAINING_RECORD(CurrentEntry,
|
|
KD_DISPATCH_TABLE,
|
|
KdProvidersList);
|
|
|
|
/* Call it */
|
|
CurrentTable->KdpPrintRoutine(String, Length);
|
|
|
|
/* Next Table */
|
|
CurrentEntry = CurrentEntry->Flink;
|
|
}
|
|
|
|
/* Call the Wrapper Routine */
|
|
if (WrapperTable.KdpPrintRoutine)
|
|
WrapperTable.KdpPrintRoutine(String, Length);
|
|
|
|
/* Return the Length */
|
|
return Length;
|
|
}
|
|
|
|
/* EOF */
|