diff --git a/ntoskrnl/kd/kdio.c b/ntoskrnl/kd/kdio.c index 92b431b426f..4705c182b3d 100644 --- a/ntoskrnl/kd/kdio.c +++ b/ntoskrnl/kd/kdio.c @@ -42,14 +42,6 @@ CPPORT SerialPortInfo = {0, DEFAULT_DEBUG_BAUD_RATE, 0}; static CHAR KdpScreenLineBuffer[KdpScreenLineLengthDefault + 1] = ""; static ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0; -const ULONG KdpDmesgBufferSize = 128 * 1024; // 512*1024; // 5*1024*1024; -PCHAR KdpDmesgBuffer = NULL; -volatile ULONG KdpDmesgCurrentPosition = 0; -volatile ULONG KdpDmesgFreeBytes = 0; -volatile ULONG KdbDmesgTotalWritten = 0; -volatile BOOLEAN KdbpIsInDmesgMode = FALSE; -static KSPIN_LOCK KdpDmesgLogSpinLock; - KDP_DEBUG_MODE KdpDebugMode; LIST_ENTRY KdProviders = {&KdProviders, &KdProviders}; KD_DISPATCH_TABLE DispatchTable[KdMax]; @@ -410,20 +402,12 @@ KdpScreenRelease(VOID) } } -/* - * Screen debug logger function KdpScreenPrint() writes text strings into - * KdpDmesgBuffer, using it as a circular buffer. KdpDmesgBuffer contents could - * be later (re)viewed using dmesg command of kdbg. KdpScreenPrint() protects - * KdpDmesgBuffer from simultaneous writes by use of KdpDmesgLogSpinLock. - */ static VOID NTAPI KdpScreenPrint(PCHAR String, ULONG Length) { PCHAR pch = String; - KIRQL OldIrql; - ULONG beg, end, num; while (pch < String + Length && *pch) { @@ -467,47 +451,6 @@ KdpScreenPrint(PCHAR String, HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos); KdpScreenLineBufferPos = KdpScreenLineLength; } - - /* Dmesg: store the string in the buffer to show it later */ - if (KdbpIsInDmesgMode) - return; - - if (KdpDmesgBuffer == NULL) - return; - - /* Acquire the printing spinlock without waiting at raised IRQL */ - OldIrql = KdpAcquireLock(&KdpDmesgLogSpinLock); - - /* Invariant: always_true(KdpDmesgFreeBytes == KdpDmesgBufferSize); - * set num to min(KdpDmesgFreeBytes, Length). - */ - num = (Length < KdpDmesgFreeBytes) ? Length : KdpDmesgFreeBytes; - beg = KdpDmesgCurrentPosition; - if (num != 0) - { - end = (beg + num) % KdpDmesgBufferSize; - if (end > beg) - { - RtlCopyMemory(KdpDmesgBuffer + beg, String, Length); - } - else - { - RtlCopyMemory(KdpDmesgBuffer + beg, String, KdpDmesgBufferSize - beg); - RtlCopyMemory(KdpDmesgBuffer, String + (KdpDmesgBufferSize - beg), end); - } - KdpDmesgCurrentPosition = end; - - /* Counting the total bytes written */ - KdbDmesgTotalWritten += num; - } - - /* Release the spinlock */ - KdpReleaseLock(&KdpDmesgLogSpinLock, OldIrql); - - /* Optional step(?): find out a way to notify about buffer exhaustion, - * and possibly fall into kbd to use dmesg command: user will read - * debug strings before they will be wiped over by next writes. - */ } VOID @@ -528,22 +471,9 @@ KdpScreenInit(PKD_DISPATCH_TABLE DispatchTable, } else if (BootPhase == 1) { - /* Allocate a buffer for dmesg log buffer. +1 for terminating null, - * see kdbp_cli.c:KdbpCmdDmesg()/2 - */ - KdpDmesgBuffer = ExAllocatePoolZero(NonPagedPool, - KdpDmesgBufferSize + 1, - TAG_KDBG); - /* Ignore failure if KdpDmesgBuffer is NULL */ - KdpDmesgFreeBytes = KdpDmesgBufferSize; - KdbDmesgTotalWritten = 0; - /* Take control of the display */ KdpScreenAcquire(); - /* Initialize spinlock */ - KeInitializeSpinLock(&KdpDmesgLogSpinLock); - HalDisplayString("\r\n Screen debugging enabled\r\n\r\n"); } } diff --git a/ntoskrnl/kdbg/kdb_symbols.c b/ntoskrnl/kdbg/kdb_symbols.c index f2e0088d006..dc1e8e5b3f4 100644 --- a/ntoskrnl/kdbg/kdb_symbols.c +++ b/ntoskrnl/kdbg/kdb_symbols.c @@ -17,6 +17,14 @@ /* GLOBALS ******************************************************************/ +const ULONG KdpDmesgBufferSize = 128 * 1024; // 512*1024; // 5*1024*1024; +PCHAR KdpDmesgBuffer = NULL; +volatile ULONG KdpDmesgCurrentPosition = 0; +volatile ULONG KdpDmesgFreeBytes = 0; +volatile ULONG KdbDmesgTotalWritten = 0; +volatile BOOLEAN KdbpIsInDmesgMode = FALSE; +static KSPIN_LOCK KdpDmesgLogSpinLock; + typedef struct _IMAGE_SYMBOL_INFO_CACHE { LIST_ENTRY ListEntry; @@ -31,6 +39,47 @@ static LIST_ENTRY SymbolsToLoad; static KSPIN_LOCK SymbolsToLoadLock; static KEVENT SymbolsToLoadEvent; +/* LOCKING FUNCTIONS *********************************************************/ + +KIRQL +NTAPI +KdbAcquireLock(IN PKSPIN_LOCK SpinLock) +{ + KIRQL OldIrql; + + /* Acquire the spinlock without waiting at raised IRQL */ + while (TRUE) + { + /* Loop until the spinlock becomes available */ + while (!KeTestSpinLock(SpinLock)); + + /* Spinlock is free, raise IRQL to high level */ + KeRaiseIrql(HIGH_LEVEL, &OldIrql); + + /* Try to get the spinlock */ + if (KeTryToAcquireSpinLockAtDpcLevel(SpinLock)) + break; + + /* Someone else got the spinlock, lower IRQL back */ + KeLowerIrql(OldIrql); + } + + return OldIrql; +} + +VOID +NTAPI +KdbReleaseLock(IN PKSPIN_LOCK SpinLock, + IN KIRQL OldIrql) +{ + /* Release the spinlock */ + KiReleaseSpinLock(SpinLock); + // KeReleaseSpinLockFromDpcLevel(SpinLock); + + /* Restore the old IRQL */ + KeLowerIrql(OldIrql); +} + /* FUNCTIONS ****************************************************************/ static @@ -330,13 +379,61 @@ KdbSymProcessSymbols( KeSetEvent(&SymbolsToLoadEvent, IO_NO_INCREMENT, FALSE); } +/* + * Debug logger function KdbDebugPrint() writes text messages into + * KdpDmesgBuffer, using it as a circular buffer. KdpDmesgBuffer contents could + * be later (re)viewed using dmesg command of kdbg. KdbDebugPrint() protects + * KdpDmesgBuffer from simultaneous writes by use of KdpDmesgLogSpinLock. + */ VOID NTAPI KdbDebugPrint( PCH Message, ULONG Length) { - /* Nothing here */ + KIRQL OldIrql; + ULONG beg, end, num; + + /* Dmesg: store Message in the buffer to show it later */ + if (KdbpIsInDmesgMode) + return; + + if (KdpDmesgBuffer == NULL) + return; + + /* Acquire the printing spinlock without waiting at raised IRQL */ + OldIrql = KdbAcquireLock(&KdpDmesgLogSpinLock); + + /* Invariant: always_true(KdpDmesgFreeBytes == KdpDmesgBufferSize); + * set num to min(KdpDmesgFreeBytes, Length). + */ + num = (Length < KdpDmesgFreeBytes) ? Length : KdpDmesgFreeBytes; + beg = KdpDmesgCurrentPosition; + if (num != 0) + { + end = (beg + num) % KdpDmesgBufferSize; + if (end > beg) + { + RtlCopyMemory(KdpDmesgBuffer + beg, Message, Length); + } + else + { + RtlCopyMemory(KdpDmesgBuffer + beg, Message, KdpDmesgBufferSize - beg); + RtlCopyMemory(KdpDmesgBuffer, Message + (KdpDmesgBufferSize - beg), end); + } + KdpDmesgCurrentPosition = end; + + /* Counting the total bytes written */ + KdbDmesgTotalWritten += num; + } + + /* Release the spinlock */ + KdbReleaseLock(&KdpDmesgLogSpinLock, OldIrql); + + /* Optional step(?): find out a way to notify about buffer exhaustion, + * and possibly fall into kbd to use dmesg command: user will read + * debug messages before they will be wiped over by next writes. + */ } @@ -426,6 +523,19 @@ KdbInitialize( NTSTATUS Status; KIRQL OldIrql; + /* Allocate a buffer for dmesg log buffer. +1 for terminating null, + * see kdbp_cli.c:KdbpCmdDmesg()/2 + */ + KdpDmesgBuffer = ExAllocatePoolZero(NonPagedPool, + KdpDmesgBufferSize + 1, + TAG_KDBG); + /* Ignore failure if KdpDmesgBuffer is NULL */ + KdpDmesgFreeBytes = KdpDmesgBufferSize; + KdbDmesgTotalWritten = 0; + + /* Initialize spinlock */ + KeInitializeSpinLock(&KdpDmesgLogSpinLock); + /* Launch our worker thread */ InitializeListHead(&SymbolsToLoad); KeInitializeSpinLock(&SymbolsToLoadLock);