2005-04-25 14:44:48 +00:00
|
|
|
/*
|
|
|
|
* 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>
|
2011-07-27 13:07:32 +00:00
|
|
|
#include <reactos/buildno.h>
|
2023-03-28 08:20:20 +00:00
|
|
|
#include "kd.h"
|
2023-03-20 16:49:15 +00:00
|
|
|
#include "kdterminal.h"
|
2023-04-04 21:38:32 +00:00
|
|
|
#ifdef KDBG
|
|
|
|
#include "../kdbg/kdb.h"
|
|
|
|
#endif
|
2020-04-06 21:48:01 +00:00
|
|
|
|
2016-10-06 19:01:33 +00:00
|
|
|
#define NDEBUG
|
2008-08-30 16:31:06 +00:00
|
|
|
#include <debug.h>
|
2005-04-25 14:44:48 +00:00
|
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
|
2009-10-07 19:57:40 +00:00
|
|
|
#define KdpBufferSize (1024 * 512)
|
2019-11-17 15:44:22 +00:00
|
|
|
static BOOLEAN KdpLoggingEnabled = FALSE;
|
|
|
|
static PCHAR KdpDebugBuffer = NULL;
|
|
|
|
static volatile ULONG KdpCurrentPosition = 0;
|
|
|
|
static volatile ULONG KdpFreeBytes = 0;
|
|
|
|
static KSPIN_LOCK KdpDebugLogSpinLock;
|
|
|
|
static KEVENT KdpLoggerThreadEvent;
|
|
|
|
static HANDLE KdpLogFileHandle;
|
2011-11-21 05:28:08 +00:00
|
|
|
ANSI_STRING KdpLogFileName = RTL_CONSTANT_STRING("\\SystemRoot\\debug.log");
|
2005-04-25 14:44:48 +00:00
|
|
|
|
2019-11-17 15:44:22 +00:00
|
|
|
static KSPIN_LOCK KdpSerialSpinLock;
|
2013-05-07 00:14:36 +00:00
|
|
|
ULONG SerialPortNumber = DEFAULT_DEBUG_PORT;
|
|
|
|
CPPORT SerialPortInfo = {0, DEFAULT_DEBUG_BAUD_RATE, 0};
|
2005-04-25 14:44:48 +00:00
|
|
|
|
2013-04-04 19:29:36 +00:00
|
|
|
#define KdpScreenLineLengthDefault 80
|
2019-11-17 15:44:22 +00:00
|
|
|
static CHAR KdpScreenLineBuffer[KdpScreenLineLengthDefault + 1] = "";
|
|
|
|
static ULONG KdpScreenLineBufferPos = 0, KdpScreenLineLength = 0;
|
2011-06-21 19:47:13 +00:00
|
|
|
|
2020-04-12 07:30:32 +00:00
|
|
|
KDP_DEBUG_MODE KdpDebugMode;
|
|
|
|
LIST_ENTRY KdProviders = {&KdProviders, &KdProviders};
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
KD_DISPATCH_TABLE DispatchTable[KdMax] = {0};
|
2020-04-12 07:30:32 +00:00
|
|
|
|
2022-11-18 16:44:29 +00:00
|
|
|
PKDP_INIT_ROUTINE InitRoutines[KdMax] =
|
|
|
|
{
|
|
|
|
KdpScreenInit,
|
|
|
|
KdpSerialInit,
|
|
|
|
KdpDebugLogInit,
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
#ifdef KDBG // See kdb_cli.c
|
2022-11-18 16:44:29 +00:00
|
|
|
KdpKdbgInit
|
|
|
|
#endif
|
|
|
|
};
|
2020-04-12 07:30:32 +00:00
|
|
|
|
2020-04-09 12:31:47 +00:00
|
|
|
static ULONG KdbgNextApiNumber = DbgKdContinueApi;
|
|
|
|
static CONTEXT KdbgContext;
|
|
|
|
static EXCEPTION_RECORD64 KdbgExceptionRecord;
|
|
|
|
static BOOLEAN KdbgFirstChanceException;
|
|
|
|
static NTSTATUS KdbgContinueStatus = STATUS_SUCCESS;
|
|
|
|
|
2019-11-17 15:44:22 +00:00
|
|
|
/* LOCKING FUNCTIONS *********************************************************/
|
|
|
|
|
|
|
|
KIRQL
|
|
|
|
NTAPI
|
2022-11-24 00:44:03 +00:00
|
|
|
KdbpAcquireLock(
|
|
|
|
_In_ PKSPIN_LOCK SpinLock)
|
2019-11-17 15:44:22 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2005-04-25 14:44:48 +00:00
|
|
|
|
|
|
|
VOID
|
2008-11-29 20:47:48 +00:00
|
|
|
NTAPI
|
2022-11-24 00:44:03 +00:00
|
|
|
KdbpReleaseLock(
|
|
|
|
_In_ PKSPIN_LOCK SpinLock,
|
|
|
|
_In_ KIRQL OldIrql)
|
2019-11-17 15:44:22 +00:00
|
|
|
{
|
|
|
|
/* Release the spinlock */
|
|
|
|
KiReleaseSpinLock(SpinLock);
|
|
|
|
// KeReleaseSpinLockFromDpcLevel(SpinLock);
|
|
|
|
|
|
|
|
/* Restore the old IRQL */
|
|
|
|
KeLowerIrql(OldIrql);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FILE DEBUG LOG FUNCTIONS **************************************************/
|
|
|
|
|
|
|
|
static VOID
|
|
|
|
NTAPI
|
2009-10-07 19:57:40 +00:00
|
|
|
KdpLoggerThread(PVOID Context)
|
2005-04-25 14:44:48 +00:00
|
|
|
{
|
2009-10-07 19:57:40 +00:00
|
|
|
ULONG beg, end, num;
|
2005-04-25 14:44:48 +00:00
|
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
|
2020-11-12 00:22:46 +00:00
|
|
|
ASSERT(ExGetPreviousMode() == KernelMode);
|
|
|
|
|
2009-10-07 19:57:40 +00:00
|
|
|
KdpLoggingEnabled = TRUE;
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
2019-11-17 15:44:22 +00:00
|
|
|
KeWaitForSingleObject(&KdpLoggerThreadEvent, Executive, KernelMode, FALSE, NULL);
|
2009-10-07 19:57:40 +00:00
|
|
|
|
|
|
|
/* Bug */
|
2011-07-07 19:18:16 +00:00
|
|
|
/* Keep KdpCurrentPosition and KdpFreeBytes values in local
|
|
|
|
* variables to avoid their possible change from Producer part,
|
|
|
|
* KdpPrintToLogFile function
|
|
|
|
*/
|
2009-10-07 19:57:40 +00:00
|
|
|
end = KdpCurrentPosition;
|
|
|
|
num = KdpFreeBytes;
|
2011-07-07 19:18:16 +00:00
|
|
|
|
|
|
|
/* Now securely calculate values, based on local variables */
|
2009-10-07 19:57:40 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-10-07 20:04:17 +00:00
|
|
|
(VOID)InterlockedExchangeAddUL(&KdpFreeBytes, num);
|
2009-10-07 19:57:40 +00:00
|
|
|
}
|
2005-04-25 14:44:48 +00:00
|
|
|
}
|
|
|
|
|
2019-11-17 15:44:22 +00:00
|
|
|
static VOID
|
2008-11-29 20:47:48 +00:00
|
|
|
NTAPI
|
2023-03-27 23:33:55 +00:00
|
|
|
KdpPrintToLogFile(
|
|
|
|
_In_ PCCH String,
|
|
|
|
_In_ ULONG Length)
|
2005-04-25 14:44:48 +00:00
|
|
|
{
|
2009-10-07 19:57:40 +00:00
|
|
|
KIRQL OldIrql;
|
2019-11-17 15:44:22 +00:00
|
|
|
ULONG beg, end, num;
|
2009-10-07 19:57:40 +00:00
|
|
|
|
|
|
|
if (KdpDebugBuffer == NULL) return;
|
|
|
|
|
|
|
|
/* Acquire the printing spinlock without waiting at raised IRQL */
|
2022-11-24 00:44:03 +00:00
|
|
|
OldIrql = KdbpAcquireLock(&KdpDebugLogSpinLock);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2009-10-07 19:57:40 +00:00
|
|
|
beg = KdpCurrentPosition;
|
2023-01-09 15:08:07 +00:00
|
|
|
num = min(Length, KdpFreeBytes);
|
2009-10-07 19:57:40 +00:00
|
|
|
if (num != 0)
|
2005-07-26 15:15:18 +00:00
|
|
|
{
|
2009-10-07 19:57:40 +00:00
|
|
|
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);
|
|
|
|
}
|
2005-07-26 15:15:18 +00:00
|
|
|
}
|
2009-10-07 19:57:40 +00:00
|
|
|
|
2019-11-17 15:44:22 +00:00
|
|
|
/* Release the spinlock */
|
2022-11-24 00:44:03 +00:00
|
|
|
KdbpReleaseLock(&KdpDebugLogSpinLock, OldIrql);
|
2009-10-07 19:57:40 +00:00
|
|
|
|
|
|
|
/* Signal the logger thread */
|
|
|
|
if (OldIrql <= DISPATCH_LEVEL && KdpLoggingEnabled)
|
2019-11-17 15:44:22 +00:00
|
|
|
KeSetEvent(&KdpLoggerThreadEvent, IO_NO_INCREMENT, FALSE);
|
2005-04-25 14:44:48 +00:00
|
|
|
}
|
|
|
|
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
NTSTATUS
|
2008-11-29 20:47:48 +00:00
|
|
|
NTAPI
|
2023-01-09 11:31:03 +00:00
|
|
|
KdpDebugLogInit(
|
|
|
|
_In_ PKD_DISPATCH_TABLE DispatchTable,
|
|
|
|
_In_ ULONG BootPhase)
|
2005-04-25 14:44:48 +00:00
|
|
|
{
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
if (!KdpDebugMode.File)
|
|
|
|
return STATUS_PORT_DISCONNECTED;
|
2005-07-30 16:25:35 +00:00
|
|
|
|
2005-04-25 14:44:48 +00:00
|
|
|
if (BootPhase == 0)
|
|
|
|
{
|
|
|
|
/* Write out the functions that we support for now */
|
2009-10-07 19:57:40 +00:00
|
|
|
DispatchTable->KdpPrintRoutine = KdpPrintToLogFile;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
/* Register for BootPhase 1 initialization and as a Provider */
|
|
|
|
DispatchTable->KdpInitRoutine = KdpDebugLogInit;
|
2005-04-25 14:44:48 +00:00
|
|
|
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
|
2009-10-07 19:57:40 +00:00
|
|
|
}
|
|
|
|
else if (BootPhase == 1)
|
|
|
|
{
|
|
|
|
/* Allocate a buffer for debug log */
|
2022-11-18 17:08:21 +00:00
|
|
|
KdpDebugBuffer = ExAllocatePoolZero(NonPagedPool,
|
|
|
|
KdpBufferSize,
|
|
|
|
TAG_KDBG);
|
|
|
|
if (!KdpDebugBuffer)
|
|
|
|
{
|
|
|
|
KdpDebugMode.File = FALSE;
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
RemoveEntryList(&DispatchTable->KdProvidersList);
|
|
|
|
return STATUS_NO_MEMORY;
|
2022-11-18 17:08:21 +00:00
|
|
|
}
|
2009-10-07 19:57:40 +00:00
|
|
|
KdpFreeBytes = KdpBufferSize;
|
|
|
|
|
|
|
|
/* Initialize spinlock */
|
|
|
|
KeInitializeSpinLock(&KdpDebugLogSpinLock);
|
2021-02-15 22:20:15 +00:00
|
|
|
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
/* Register for later BootPhase 2 reinitialization */
|
|
|
|
DispatchTable->KdpInitRoutine = KdpDebugLogInit;
|
|
|
|
|
2023-03-20 01:28:16 +00:00
|
|
|
/* Announce ourselves */
|
2023-03-14 17:50:30 +00:00
|
|
|
HalDisplayString(" File log debugging enabled\r\n");
|
2005-04-25 14:44:48 +00:00
|
|
|
}
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
else if (BootPhase >= 2)
|
2005-04-25 14:44:48 +00:00
|
|
|
{
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
UNICODE_STRING FileName;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
IO_STATUS_BLOCK Iosb;
|
|
|
|
HANDLE ThreadHandle;
|
|
|
|
KPRIORITY Priority;
|
|
|
|
|
|
|
|
/* If we have already successfully opened the log file, bail out */
|
|
|
|
if (KdpLogFileHandle != NULL)
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
|
2009-10-07 19:57:40 +00:00
|
|
|
/* Setup the log name */
|
2011-11-21 05:28:08 +00:00
|
|
|
Status = RtlAnsiStringToUnicodeString(&FileName, &KdpLogFileName, TRUE);
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
goto Failure;
|
2011-11-21 05:28:08 +00:00
|
|
|
|
2005-04-25 14:44:48 +00:00
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
|
|
&FileName,
|
2019-11-17 15:44:22 +00:00
|
|
|
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
2005-04-25 14:44:48 +00:00
|
|
|
NULL,
|
|
|
|
NULL);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2009-10-07 19:57:40 +00:00
|
|
|
/* Create the log file */
|
2021-02-26 07:44:51 +00:00
|
|
|
Status = ZwCreateFile(&KdpLogFileHandle,
|
2009-10-07 19:57:40 +00:00
|
|
|
FILE_APPEND_DATA | SYNCHRONIZE,
|
2005-04-25 14:44:48 +00:00
|
|
|
&ObjectAttributes,
|
|
|
|
&Iosb,
|
|
|
|
NULL,
|
|
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
|
|
FILE_SHARE_READ,
|
2023-01-09 19:42:11 +00:00
|
|
|
FILE_OPEN_IF,
|
|
|
|
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
|
|
|
|
FILE_SEQUENTIAL_ONLY | FILE_WRITE_THROUGH,
|
2005-04-25 14:44:48 +00:00
|
|
|
NULL,
|
|
|
|
0);
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2011-11-21 05:28:08 +00:00
|
|
|
RtlFreeUnicodeString(&FileName);
|
|
|
|
|
2019-11-17 15:44:22 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2021-02-26 07:44:51 +00:00
|
|
|
{
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
DPRINT1("Failed to open log file: 0x%08lx\n", Status);
|
|
|
|
|
|
|
|
/* Schedule an I/O reinitialization if needed */
|
|
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
|
|
|
|
Status == STATUS_OBJECT_PATH_NOT_FOUND)
|
|
|
|
{
|
|
|
|
DispatchTable->KdpInitRoutine = KdpDebugLogInit;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
goto Failure;
|
2021-02-26 07:44:51 +00:00
|
|
|
}
|
2009-10-07 19:57:40 +00:00
|
|
|
|
2023-01-09 19:42:11 +00:00
|
|
|
/** HACK for FILE_APPEND_DATA **
|
|
|
|
** Remove once CORE-18789 is fixed. **
|
|
|
|
** Enforce to go to the end of file **/
|
|
|
|
{
|
|
|
|
FILE_STANDARD_INFORMATION FileInfo;
|
|
|
|
FILE_POSITION_INFORMATION FilePosInfo;
|
|
|
|
|
|
|
|
Status = ZwQueryInformationFile(KdpLogFileHandle,
|
|
|
|
&Iosb,
|
|
|
|
&FileInfo,
|
|
|
|
sizeof(FileInfo),
|
|
|
|
FileStandardInformation);
|
|
|
|
DPRINT("Status: 0x%08lx - EOF offset: %I64d\n",
|
|
|
|
Status, FileInfo.EndOfFile.QuadPart);
|
|
|
|
|
|
|
|
Status = ZwQueryInformationFile(KdpLogFileHandle,
|
|
|
|
&Iosb,
|
|
|
|
&FilePosInfo,
|
|
|
|
sizeof(FilePosInfo),
|
|
|
|
FilePositionInformation);
|
|
|
|
DPRINT("Status: 0x%08lx - Position: %I64d\n",
|
|
|
|
Status, FilePosInfo.CurrentByteOffset.QuadPart);
|
|
|
|
|
|
|
|
FilePosInfo.CurrentByteOffset.QuadPart = FileInfo.EndOfFile.QuadPart;
|
|
|
|
Status = ZwSetInformationFile(KdpLogFileHandle,
|
|
|
|
&Iosb,
|
|
|
|
&FilePosInfo,
|
|
|
|
sizeof(FilePosInfo),
|
|
|
|
FilePositionInformation);
|
|
|
|
DPRINT("ZwSetInformationFile(FilePositionInfo) returned: 0x%08lx\n", Status);
|
|
|
|
}
|
|
|
|
/** END OF HACK **/
|
|
|
|
|
2009-10-07 19:57:40 +00:00
|
|
|
KeInitializeEvent(&KdpLoggerThreadEvent, SynchronizationEvent, TRUE);
|
|
|
|
|
|
|
|
/* Create the logger thread */
|
|
|
|
Status = PsCreateSystemThread(&ThreadHandle,
|
|
|
|
THREAD_ALL_ACCESS,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
KdpLoggerThread,
|
|
|
|
NULL);
|
2019-11-17 15:44:22 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
DPRINT1("Failed to create log file thread: 0x%08lx\n", Status);
|
2021-02-26 07:44:51 +00:00
|
|
|
ZwClose(KdpLogFileHandle);
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
goto Failure;
|
2019-11-17 15:44:22 +00:00
|
|
|
}
|
2009-10-07 19:57:40 +00:00
|
|
|
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
Priority = HIGH_PRIORITY;
|
2021-02-26 07:44:51 +00:00
|
|
|
ZwSetInformationThread(ThreadHandle,
|
2009-10-07 19:57:40 +00:00
|
|
|
ThreadPriority,
|
|
|
|
&Priority,
|
|
|
|
sizeof(Priority));
|
2020-11-12 00:22:46 +00:00
|
|
|
|
|
|
|
ZwClose(ThreadHandle);
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
return Status;
|
|
|
|
|
|
|
|
Failure:
|
|
|
|
KdpFreeBytes = 0;
|
|
|
|
ExFreePoolWithTag(KdpDebugBuffer, TAG_KDBG);
|
|
|
|
KdpDebugBuffer = NULL;
|
|
|
|
KdpDebugMode.File = FALSE;
|
|
|
|
RemoveEntryList(&DispatchTable->KdProvidersList);
|
2005-04-25 14:44:48 +00:00
|
|
|
}
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
|
|
|
|
return Status;
|
2005-04-25 14:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SERIAL FUNCTIONS **********************************************************/
|
|
|
|
|
2022-11-18 16:44:29 +00:00
|
|
|
static VOID
|
2008-11-29 20:47:48 +00:00
|
|
|
NTAPI
|
2023-03-27 23:33:55 +00:00
|
|
|
KdpSerialPrint(
|
|
|
|
_In_ PCCH String,
|
|
|
|
_In_ ULONG Length)
|
2005-04-25 14:44:48 +00:00
|
|
|
{
|
2023-03-27 23:33:55 +00:00
|
|
|
PCCH pch = String;
|
2009-03-29 13:15:03 +00:00
|
|
|
KIRQL OldIrql;
|
2005-04-25 14:44:48 +00:00
|
|
|
|
2009-03-29 13:15:03 +00:00
|
|
|
/* Acquire the printing spinlock without waiting at raised IRQL */
|
2022-11-24 00:44:03 +00:00
|
|
|
OldIrql = KdbpAcquireLock(&KdpSerialSpinLock);
|
2009-03-29 13:15:03 +00:00
|
|
|
|
2022-11-18 16:44:29 +00:00
|
|
|
/* Output the string */
|
|
|
|
while (pch < String + Length && *pch)
|
2005-04-25 14:44:48 +00:00
|
|
|
{
|
|
|
|
if (*pch == '\n')
|
|
|
|
{
|
|
|
|
KdPortPutByteEx(&SerialPortInfo, '\r');
|
|
|
|
}
|
|
|
|
KdPortPutByteEx(&SerialPortInfo, *pch);
|
2023-03-27 23:33:55 +00:00
|
|
|
++pch;
|
2005-04-25 14:44:48 +00:00
|
|
|
}
|
2009-03-29 13:15:03 +00:00
|
|
|
|
2019-11-17 15:44:22 +00:00
|
|
|
/* Release the spinlock */
|
2022-11-24 00:44:03 +00:00
|
|
|
KdbpReleaseLock(&KdpSerialSpinLock, OldIrql);
|
2005-04-25 14:44:48 +00:00
|
|
|
}
|
|
|
|
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
NTSTATUS
|
2008-11-29 20:47:48 +00:00
|
|
|
NTAPI
|
2023-01-09 11:31:03 +00:00
|
|
|
KdpSerialInit(
|
|
|
|
_In_ PKD_DISPATCH_TABLE DispatchTable,
|
|
|
|
_In_ ULONG BootPhase)
|
2005-04-25 14:44:48 +00:00
|
|
|
{
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
if (!KdpDebugMode.Serial)
|
|
|
|
return STATUS_PORT_DISCONNECTED;
|
2005-04-25 14:44:48 +00:00
|
|
|
|
|
|
|
if (BootPhase == 0)
|
|
|
|
{
|
|
|
|
/* Write out the functions that we support for now */
|
2022-11-18 16:44:29 +00:00
|
|
|
DispatchTable->KdpPrintRoutine = KdpSerialPrint;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2005-04-25 14:44:48 +00:00
|
|
|
/* Initialize the Port */
|
2013-05-07 00:14:36 +00:00
|
|
|
if (!KdPortInitializeEx(&SerialPortInfo, SerialPortNumber))
|
2005-10-02 09:42:12 +00:00
|
|
|
{
|
|
|
|
KdpDebugMode.Serial = FALSE;
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
return STATUS_DEVICE_DOES_NOT_EXIST;
|
2005-10-02 09:42:12 +00:00
|
|
|
}
|
2013-05-07 00:14:36 +00:00
|
|
|
KdComPortInUse = SerialPortInfo.Address;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2009-03-29 13:15:03 +00:00
|
|
|
/* Initialize spinlock */
|
|
|
|
KeInitializeSpinLock(&KdpSerialSpinLock);
|
|
|
|
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
/* Register for BootPhase 1 initialization and as a Provider */
|
|
|
|
DispatchTable->KdpInitRoutine = KdpSerialInit;
|
2005-04-25 14:44:48 +00:00
|
|
|
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
|
|
|
|
}
|
2021-02-15 22:20:15 +00:00
|
|
|
else if (BootPhase == 1)
|
2005-04-25 14:44:48 +00:00
|
|
|
{
|
2023-03-20 01:28:16 +00:00
|
|
|
/* Announce ourselves */
|
2023-03-14 17:50:30 +00:00
|
|
|
HalDisplayString(" Serial debugging enabled\r\n");
|
2005-05-09 01:38:29 +00:00
|
|
|
}
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
2005-04-25 14:44:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* SCREEN FUNCTIONS **********************************************************/
|
|
|
|
|
2019-11-17 15:44:22 +00:00
|
|
|
VOID
|
|
|
|
KdpScreenAcquire(VOID)
|
|
|
|
{
|
|
|
|
if (InbvIsBootDriverInstalled() /* &&
|
|
|
|
!InbvCheckDisplayOwnership() */)
|
|
|
|
{
|
|
|
|
/* Acquire ownership and reset the display */
|
|
|
|
InbvAcquireDisplayOwnership();
|
|
|
|
InbvResetDisplay();
|
2020-05-09 14:20:57 +00:00
|
|
|
InbvSolidColorFill(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1, BV_COLOR_BLACK);
|
|
|
|
InbvSetTextColor(BV_COLOR_WHITE);
|
2019-11-17 15:44:22 +00:00
|
|
|
InbvInstallDisplayStringFilter(NULL);
|
|
|
|
InbvEnableDisplayString(TRUE);
|
2020-04-06 21:48:01 +00:00
|
|
|
InbvSetScrollRegion(0, 0, SCREEN_WIDTH - 1, SCREEN_HEIGHT - 1);
|
2019-11-17 15:44:22 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-26 16:19:11 +00:00
|
|
|
// extern VOID NTAPI InbvSetDisplayOwnership(IN BOOLEAN DisplayOwned);
|
|
|
|
|
2019-11-17 15:44:22 +00:00
|
|
|
VOID
|
|
|
|
KdpScreenRelease(VOID)
|
|
|
|
{
|
|
|
|
if (InbvIsBootDriverInstalled()&&
|
|
|
|
InbvCheckDisplayOwnership())
|
|
|
|
{
|
|
|
|
/* Release the display */
|
2019-12-26 16:19:11 +00:00
|
|
|
// InbvSetDisplayOwnership(FALSE);
|
2019-11-17 15:44:22 +00:00
|
|
|
InbvNotifyDisplayOwnershipLost(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static VOID
|
2008-11-29 20:47:48 +00:00
|
|
|
NTAPI
|
2023-03-27 23:33:55 +00:00
|
|
|
KdpScreenPrint(
|
|
|
|
_In_ PCCH String,
|
|
|
|
_In_ ULONG Length)
|
- More sharing between ntdll/ntoskrnl: shared Dbg code.
- Added NtCreateDebugObject, NtDebugContinue, NtQueryDebugFilterState, NtSetDebugFilterState, NtWaitForDebugEvent to system call list.
- Added some debug constants to headers
- Updated RtlpCheckForActiveDebugger in ntoskrnl to return whatever we're expecting as the "normal" case.
- Added RtlpSetInDbgPrint to rtl support library for special DbgPrint implementation difference in user-mode
- Removed all the deprecated debug APIs in ntdll.
- Implemented NtQueryDebugFilterState and NtSetDebugFilterState based on royce's implementation.
- Started modifications on KeDebugService, and implemented DebugService in rtl
- Implemented all the Dbg* APIs in RTL.
- Implemented DbgUiConnectToDbg, DbgUiContinue, DbgUiWaitStateChange, DbgUiRemoteBreakin, DbgUiIssueRemoteBreakin
- Changed KD Print callbacks to also receive the length of the string.
Right now, one call that should be shared still isn't (the final DebugPrint call) because calling KeDebugService from kernel-mode seems to cause a hang. Also, DebugService does not currently cause an exception like it should (instead it still calls the Kdp handler), because those changes would've made the patch even bigger and are still untested.
svn path=/trunk/; revision=18078
2005-09-26 04:59:48 +00:00
|
|
|
{
|
2023-03-27 23:33:55 +00:00
|
|
|
PCCH pch = String;
|
2011-06-21 19:47:13 +00:00
|
|
|
|
2022-11-18 16:44:29 +00:00
|
|
|
while (pch < String + Length && *pch)
|
2011-06-21 19:47:13 +00:00
|
|
|
{
|
2019-11-17 15:44:22 +00:00
|
|
|
if (*pch == '\b')
|
2011-06-21 19:47:13 +00:00
|
|
|
{
|
|
|
|
/* HalDisplayString does not support '\b'. Workaround it and use '\r' */
|
2019-11-17 15:44:22 +00:00
|
|
|
if (KdpScreenLineLength > 0)
|
2011-06-21 19:47:13 +00:00
|
|
|
{
|
|
|
|
/* Remove last character from buffer */
|
|
|
|
KdpScreenLineBuffer[--KdpScreenLineLength] = '\0';
|
|
|
|
KdpScreenLineBufferPos = KdpScreenLineLength;
|
|
|
|
|
|
|
|
/* Clear row and print line again */
|
|
|
|
HalDisplayString("\r");
|
|
|
|
HalDisplayString(KdpScreenLineBuffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
KdpScreenLineBuffer[KdpScreenLineLength++] = *pch;
|
|
|
|
KdpScreenLineBuffer[KdpScreenLineLength] = '\0';
|
|
|
|
}
|
|
|
|
|
2019-11-17 15:44:22 +00:00
|
|
|
if (*pch == '\n' || KdpScreenLineLength == KdpScreenLineLengthDefault)
|
2011-06-21 19:47:13 +00:00
|
|
|
{
|
|
|
|
/* Print buffered characters */
|
2019-11-17 15:44:22 +00:00
|
|
|
if (KdpScreenLineBufferPos != KdpScreenLineLength)
|
2011-06-21 19:47:13 +00:00
|
|
|
HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos);
|
|
|
|
|
|
|
|
/* Clear line buffer */
|
|
|
|
KdpScreenLineBuffer[0] = '\0';
|
|
|
|
KdpScreenLineLength = KdpScreenLineBufferPos = 0;
|
|
|
|
}
|
2011-07-07 19:18:16 +00:00
|
|
|
|
2011-06-21 19:47:13 +00:00
|
|
|
++pch;
|
|
|
|
}
|
2011-07-07 19:18:16 +00:00
|
|
|
|
2011-06-21 19:47:13 +00:00
|
|
|
/* Print buffered characters */
|
2019-11-17 15:44:22 +00:00
|
|
|
if (KdpScreenLineBufferPos != KdpScreenLineLength)
|
2011-06-21 19:47:13 +00:00
|
|
|
{
|
|
|
|
HalDisplayString(KdpScreenLineBuffer + KdpScreenLineBufferPos);
|
|
|
|
KdpScreenLineBufferPos = KdpScreenLineLength;
|
|
|
|
}
|
- More sharing between ntdll/ntoskrnl: shared Dbg code.
- Added NtCreateDebugObject, NtDebugContinue, NtQueryDebugFilterState, NtSetDebugFilterState, NtWaitForDebugEvent to system call list.
- Added some debug constants to headers
- Updated RtlpCheckForActiveDebugger in ntoskrnl to return whatever we're expecting as the "normal" case.
- Added RtlpSetInDbgPrint to rtl support library for special DbgPrint implementation difference in user-mode
- Removed all the deprecated debug APIs in ntdll.
- Implemented NtQueryDebugFilterState and NtSetDebugFilterState based on royce's implementation.
- Started modifications on KeDebugService, and implemented DebugService in rtl
- Implemented all the Dbg* APIs in RTL.
- Implemented DbgUiConnectToDbg, DbgUiContinue, DbgUiWaitStateChange, DbgUiRemoteBreakin, DbgUiIssueRemoteBreakin
- Changed KD Print callbacks to also receive the length of the string.
Right now, one call that should be shared still isn't (the final DebugPrint call) because calling KeDebugService from kernel-mode seems to cause a hang. Also, DebugService does not currently cause an exception like it should (instead it still calls the Kdp handler), because those changes would've made the patch even bigger and are still untested.
svn path=/trunk/; revision=18078
2005-09-26 04:59:48 +00:00
|
|
|
}
|
|
|
|
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
NTSTATUS
|
2008-11-29 20:47:48 +00:00
|
|
|
NTAPI
|
2023-01-09 11:31:03 +00:00
|
|
|
KdpScreenInit(
|
|
|
|
_In_ PKD_DISPATCH_TABLE DispatchTable,
|
|
|
|
_In_ ULONG BootPhase)
|
2005-04-25 14:44:48 +00:00
|
|
|
{
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
if (!KdpDebugMode.Screen)
|
|
|
|
return STATUS_PORT_DISCONNECTED;
|
2005-04-25 14:44:48 +00:00
|
|
|
|
|
|
|
if (BootPhase == 0)
|
|
|
|
{
|
|
|
|
/* Write out the functions that we support for now */
|
- More sharing between ntdll/ntoskrnl: shared Dbg code.
- Added NtCreateDebugObject, NtDebugContinue, NtQueryDebugFilterState, NtSetDebugFilterState, NtWaitForDebugEvent to system call list.
- Added some debug constants to headers
- Updated RtlpCheckForActiveDebugger in ntoskrnl to return whatever we're expecting as the "normal" case.
- Added RtlpSetInDbgPrint to rtl support library for special DbgPrint implementation difference in user-mode
- Removed all the deprecated debug APIs in ntdll.
- Implemented NtQueryDebugFilterState and NtSetDebugFilterState based on royce's implementation.
- Started modifications on KeDebugService, and implemented DebugService in rtl
- Implemented all the Dbg* APIs in RTL.
- Implemented DbgUiConnectToDbg, DbgUiContinue, DbgUiWaitStateChange, DbgUiRemoteBreakin, DbgUiIssueRemoteBreakin
- Changed KD Print callbacks to also receive the length of the string.
Right now, one call that should be shared still isn't (the final DebugPrint call) because calling KeDebugService from kernel-mode seems to cause a hang. Also, DebugService does not currently cause an exception like it should (instead it still calls the Kdp handler), because those changes would've made the patch even bigger and are still untested.
svn path=/trunk/; revision=18078
2005-09-26 04:59:48 +00:00
|
|
|
DispatchTable->KdpPrintRoutine = KdpScreenPrint;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
/* Register for BootPhase 1 initialization and as a Provider */
|
|
|
|
DispatchTable->KdpInitRoutine = KdpScreenInit;
|
2005-04-25 14:44:48 +00:00
|
|
|
InsertTailList(&KdProviders, &DispatchTable->KdProvidersList);
|
|
|
|
}
|
2011-07-07 19:18:16 +00:00
|
|
|
else if (BootPhase == 1)
|
|
|
|
{
|
2012-09-19 06:09:22 +00:00
|
|
|
/* Take control of the display */
|
2019-11-17 15:44:22 +00:00
|
|
|
KdpScreenAcquire();
|
2012-09-19 06:09:22 +00:00
|
|
|
|
2023-03-20 01:28:16 +00:00
|
|
|
/* Announce ourselves */
|
2023-03-14 17:50:30 +00:00
|
|
|
HalDisplayString(" Screen debugging enabled\r\n");
|
2005-05-09 01:38:29 +00:00
|
|
|
}
|
[NTOS:KD][KDBG] Rework the BootPhase >= 2 initialization of the KD/KDBG kernel debugger. (#4892)
CORE-17470
+ KdpDebugLogInit: Add resources cleanup in failure code paths.
Fix, in an NT-compatible manner, how (and when) the KD/KDBG BootPhase >=2
initialization steps are performed.
These are necessary for any functionality KDBG needs, that would depend
on the NT I/O Manager and the storage and filesystem stacks to be running.
This includes, creating the debug log file, and for KDBG, loading its
KDBinit initialization file.
As a result, file debug logging is fixed.
The old ReactOS-specific (NT-incompatible) callback we did in the middle
of IoInitSystem() is removed, in favor of a runtime mechanism that should
work on Windows as well.
The idea for this new mechanism is loosely inspired by the TDL4 rootkit,
see http://blog.w4kfu.com/public/tdl4_article/draft_tdl4article.html
but contrary to it, a specific hook is used instead, as well as the
technique of driver reinitialization:
https://web.archive.org/web/20211021050515/https://driverentry.com.br/en/blog/?p=261
Its rationale is as follows:
We want to be able to perform I/O-related initialization (starting a
logger thread for file log debugging, loading KDBinit file for KDBG,
etc.). A good place for this would be as early as possible, once the
I/O Manager has started the storage and the boot filesystem drivers.
Here is an overview of the initialization steps of the NT Kernel and
Executive:
----
KiSystemStartup(KeLoaderBlock)
if (Cpu == 0) KdInitSystem(0, KeLoaderBlock);
KiSwitchToBootStack() -> KiSystemStartupBootStack()
-> KiInitializeKernel() -> ExpInitializeExecutive(Cpu, KeLoaderBlock)
(NOTE: Any unexpected debugger break will call KdInitSystem(0, NULL); )
KdInitSystem(0, LoaderBlock) -> KdDebuggerInitialize0(LoaderBlock);
ExpInitializeExecutive(Cpu == 0): ExpInitializationPhase = 0;
HalInitSystem(0, KeLoaderBlock); <-- Sets HalInitPnpDriver callback.
...
PsInitSystem(LoaderBlock)
PsCreateSystemThread(Phase1Initialization)
Phase1Initialization(Discard): ExpInitializationPhase = 1;
HalInitSystem(1, KeLoaderBlock);
...
Early initialization of Ob, Ex, Ke.
KdInitSystem(1, KeLoaderBlock);
...
KdDebuggerInitialize1(LoaderBlock);
...
IoInitSystem(LoaderBlock);
...
----
As we can see, KdDebuggerInitialize1() is the last KD initialization
routine the kernel calls, and is called *before* the I/O Manager starts.
Thus, direct Nt/ZwCreateFile ... calls done there would fail. Also,
we want to do the I/O initialization as soon as possible. There does
not seem to be any exported way to be notified about the I/O manager
initialization steps... that is, unless we somehow become a driver and
insert ourselves in the flow!
Since we are not a regular driver, we need to invoke IoCreateDriver()
to create one. However, remember that we are currently running *before*
IoInitSystem(), the I/O subsystem is not initialized yet. Due to this,
calling IoCreateDriver(), much like any other IO functions, would lead
to a crash, because it calls
ObCreateObject(..., IoDriverObjectType, ...), and IoDriverObjectType
is non-initialized yet (it's NULL).
The chosen solution is to hook a "known" exported callback: namely, the
HalInitPnpDriver() callback (it initializes the "HAL Root Bus Driver").
It is set very early on by the HAL via the HalInitSystem(0, ...) call,
and is called early on by IoInitSystem() before any driver is loaded,
but after the I/O Manager has been minimally set up so that new drivers
can be created.
When the hook: KdpInitDriver() is called, we create our driver with
IoCreateDriver(), specifying its entrypoint KdpDriverEntry(), then
restore and call the original HalInitPnpDriver() callback.
Another possible unexplored alternative, could be to insert ourselves
in the KeLoaderBlock->LoadOrderListHead boot modules list, or in the
KeLoaderBlock->BootDriverListHead boot-driver list. (Note that while
we may be able to do this, because boot-drivers are resident in memory,
much like we are, we cannot insert ourselves in the system-driver list
however, since those drivers are expected to come from PE image files.)
Once the KdpDriverEntry() driver entrypoint is called, we register
KdpDriverReinit() for re-initialization with the I/O Manager, in order
to provide more initialization points. KdpDriverReinit() calls the KD
providers at BootPhase >= 2, and schedules further reinitializations
(at most 3 more) if any of the providers request so.
2023-01-09 18:35:18 +00:00
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
2005-04-25 14:44:48 +00:00
|
|
|
}
|
|
|
|
|
2022-11-18 16:44:29 +00:00
|
|
|
|
2005-04-25 14:44:48 +00:00
|
|
|
/* GENERAL FUNCTIONS *********************************************************/
|
|
|
|
|
2023-03-27 23:33:55 +00:00
|
|
|
static VOID
|
|
|
|
KdIoPrintString(
|
|
|
|
_In_ PCCH String,
|
|
|
|
_In_ ULONG Length)
|
|
|
|
{
|
|
|
|
PLIST_ENTRY CurrentEntry;
|
|
|
|
PKD_DISPATCH_TABLE CurrentTable;
|
|
|
|
|
|
|
|
/* Call the registered providers */
|
|
|
|
for (CurrentEntry = KdProviders.Flink;
|
|
|
|
CurrentEntry != &KdProviders;
|
|
|
|
CurrentEntry = CurrentEntry->Flink)
|
|
|
|
{
|
|
|
|
CurrentTable = CONTAINING_RECORD(CurrentEntry,
|
|
|
|
KD_DISPATCH_TABLE,
|
|
|
|
KdProvidersList);
|
|
|
|
|
|
|
|
CurrentTable->KdpPrintRoutine(String, Length);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
KdIoPuts(
|
|
|
|
_In_ PCSTR String)
|
|
|
|
{
|
|
|
|
KdIoPrintString(String, (ULONG)strlen(String));
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
__cdecl
|
|
|
|
KdIoPrintf(
|
|
|
|
_In_ PCSTR Format,
|
|
|
|
...)
|
|
|
|
{
|
|
|
|
va_list ap;
|
|
|
|
ULONG Length;
|
|
|
|
CHAR Buffer[512];
|
|
|
|
|
|
|
|
/* Format the string */
|
|
|
|
va_start(ap, Format);
|
|
|
|
Length = (ULONG)_vsnprintf(Buffer,
|
|
|
|
sizeof(Buffer),
|
|
|
|
Format,
|
|
|
|
ap);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
/* Send it to the display providers */
|
|
|
|
KdIoPrintString(Buffer, Length);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-03-29 17:38:10 +00:00
|
|
|
extern const CSTRING KdbPromptStr;
|
2017-12-08 13:41:41 +00:00
|
|
|
|
2020-03-07 22:33:57 +00:00
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
KdSendPacket(
|
2022-11-27 18:58:56 +00:00
|
|
|
_In_ ULONG PacketType,
|
|
|
|
_In_ PSTRING MessageHeader,
|
|
|
|
_In_opt_ PSTRING MessageData,
|
|
|
|
_Inout_ PKD_CONTEXT Context)
|
2020-03-07 22:33:57 +00:00
|
|
|
{
|
|
|
|
if (PacketType == PACKET_TYPE_KD_DEBUG_IO)
|
2005-04-25 14:44:48 +00:00
|
|
|
{
|
2022-11-27 18:58:56 +00:00
|
|
|
ULONG ApiNumber = ((PDBGKD_DEBUG_IO)MessageHeader->Buffer)->ApiNumber;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2022-11-27 18:58:56 +00:00
|
|
|
/* Validate API call */
|
|
|
|
if (MessageHeader->Length != sizeof(DBGKD_DEBUG_IO))
|
|
|
|
return;
|
|
|
|
if ((ApiNumber != DbgKdPrintStringApi) &&
|
|
|
|
(ApiNumber != DbgKdGetStringApi))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!MessageData)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* NOTE: MessageData->Length should be equal to
|
|
|
|
* DebugIo.u.PrintString.LengthOfString, or to
|
|
|
|
* DebugIo.u.GetString.LengthOfPromptString */
|
|
|
|
|
|
|
|
if (!KdpDebugMode.Value)
|
|
|
|
return;
|
2005-05-09 01:38:29 +00:00
|
|
|
|
2023-03-27 23:33:55 +00:00
|
|
|
/* Print the string proper */
|
|
|
|
KdIoPrintString(MessageData->Buffer, MessageData->Length);
|
2020-03-07 22:33:57 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-03-09 23:00:00 +00:00
|
|
|
else if (PacketType == PACKET_TYPE_KD_STATE_CHANGE64)
|
|
|
|
{
|
|
|
|
PDBGKD_ANY_WAIT_STATE_CHANGE WaitStateChange = (PDBGKD_ANY_WAIT_STATE_CHANGE)MessageHeader->Buffer;
|
|
|
|
if (WaitStateChange->NewState == DbgKdLoadSymbolsStateChange)
|
|
|
|
{
|
|
|
|
#ifdef KDBG
|
|
|
|
PLDR_DATA_TABLE_ENTRY LdrEntry;
|
2021-06-22 17:46:27 +00:00
|
|
|
/* Load symbols. Currently implemented only for KDBG! */
|
|
|
|
if (KdbpSymFindModule((PVOID)(ULONG_PTR)WaitStateChange->u.LoadSymbols.BaseOfDll, -1, &LdrEntry))
|
2020-03-09 23:00:00 +00:00
|
|
|
{
|
2021-06-22 17:46:27 +00:00
|
|
|
KdbSymProcessSymbols(LdrEntry, !WaitStateChange->u.LoadSymbols.UnloadSymbols);
|
2020-03-09 23:00:00 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2020-04-09 12:31:47 +00:00
|
|
|
else if (WaitStateChange->NewState == DbgKdExceptionStateChange)
|
|
|
|
{
|
|
|
|
KdbgNextApiNumber = DbgKdGetContextApi;
|
|
|
|
KdbgExceptionRecord = WaitStateChange->u.Exception.ExceptionRecord;
|
|
|
|
KdbgFirstChanceException = WaitStateChange->u.Exception.FirstChance;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
|
|
|
|
{
|
|
|
|
PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer;
|
|
|
|
if (ManipulateState->ApiNumber == DbgKdGetContextApi)
|
|
|
|
{
|
|
|
|
KD_CONTINUE_TYPE Result;
|
|
|
|
|
|
|
|
#ifdef KDBG
|
|
|
|
/* Check if this is an assertion failure */
|
|
|
|
if (KdbgExceptionRecord.ExceptionCode == STATUS_ASSERTION_FAILURE)
|
|
|
|
{
|
|
|
|
/* Bump EIP to the instruction following the int 2C */
|
2021-04-27 08:23:37 +00:00
|
|
|
KeSetContextPc(&KdbgContext, KeGetContextPc(&KdbgContext) + 2);
|
2020-04-09 12:31:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Result = KdbEnterDebuggerException(&KdbgExceptionRecord,
|
2020-11-22 17:13:51 +00:00
|
|
|
KdbgContext.SegCs & 1,
|
2020-04-09 12:31:47 +00:00
|
|
|
&KdbgContext,
|
|
|
|
KdbgFirstChanceException);
|
|
|
|
#else
|
|
|
|
/* We'll manually dump the stack for the user... */
|
|
|
|
KeRosDumpStackFrames(NULL, 0);
|
|
|
|
Result = kdHandleException;
|
|
|
|
#endif
|
|
|
|
if (Result != kdHandleException)
|
|
|
|
KdbgContinueStatus = STATUS_SUCCESS;
|
|
|
|
else
|
|
|
|
KdbgContinueStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
KdbgNextApiNumber = DbgKdSetContextApi;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else if (ManipulateState->ApiNumber == DbgKdSetContextApi)
|
|
|
|
{
|
|
|
|
KdbgNextApiNumber = DbgKdContinueApi;
|
|
|
|
return;
|
|
|
|
}
|
2020-03-09 23:00:00 +00:00
|
|
|
}
|
2020-03-07 22:33:57 +00:00
|
|
|
UNIMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
KDSTATUS
|
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.
For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.
KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
NtSetDebugFilterState() that now comes entirely from KD64.
- Remove KD variables that are now shared with KD64.
- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().
- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.
- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
KdpPrint() worker function that correctly probes and captures its arguments.
- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
by the shared code, until KD is removed and only the KD64 version of these
functions remain.
- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
helper compatible with KD64, that is called by the KD64 implementation of
KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
debugging, the prompt will appear on both. Before that the prompt was always
being displayed on COM port even if e.g. a SCREEN-only debug session was used...
- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().
KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
before using them elsewhere.
- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).
- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 21:55:36 +00:00
|
|
|
NTAPI
|
2020-03-07 22:33:57 +00:00
|
|
|
KdReceivePacket(
|
2022-11-27 18:58:56 +00:00
|
|
|
_In_ ULONG PacketType,
|
|
|
|
_Out_ PSTRING MessageHeader,
|
|
|
|
_Out_ PSTRING MessageData,
|
|
|
|
_Out_ PULONG DataLength,
|
|
|
|
_Inout_ PKD_CONTEXT Context)
|
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.
For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.
KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
NtSetDebugFilterState() that now comes entirely from KD64.
- Remove KD variables that are now shared with KD64.
- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().
- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.
- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
KdpPrint() worker function that correctly probes and captures its arguments.
- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
by the shared code, until KD is removed and only the KD64 version of these
functions remain.
- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
helper compatible with KD64, that is called by the KD64 implementation of
KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
debugging, the prompt will appear on both. Before that the prompt was always
being displayed on COM port even if e.g. a SCREEN-only debug session was used...
- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().
KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
before using them elsewhere.
- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).
- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 21:55:36 +00:00
|
|
|
{
|
2020-03-28 23:30:53 +00:00
|
|
|
#ifdef KDBG
|
2020-03-07 22:33:57 +00:00
|
|
|
STRING ResponseString;
|
2022-11-27 18:58:56 +00:00
|
|
|
PDBGKD_DEBUG_IO DebugIo;
|
|
|
|
CHAR MessageBuffer[512];
|
2020-03-07 22:33:57 +00:00
|
|
|
#endif
|
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.
For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.
KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
NtSetDebugFilterState() that now comes entirely from KD64.
- Remove KD variables that are now shared with KD64.
- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().
- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.
- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
KdpPrint() worker function that correctly probes and captures its arguments.
- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
by the shared code, until KD is removed and only the KD64 version of these
functions remain.
- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
helper compatible with KD64, that is called by the KD64 implementation of
KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
debugging, the prompt will appear on both. Before that the prompt was always
being displayed on COM port even if e.g. a SCREEN-only debug session was used...
- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().
KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
before using them elsewhere.
- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).
- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 21:55:36 +00:00
|
|
|
|
2020-03-09 23:00:00 +00:00
|
|
|
if (PacketType == PACKET_TYPE_KD_STATE_MANIPULATE)
|
|
|
|
{
|
|
|
|
PDBGKD_MANIPULATE_STATE64 ManipulateState = (PDBGKD_MANIPULATE_STATE64)MessageHeader->Buffer;
|
2020-04-09 12:31:47 +00:00
|
|
|
RtlZeroMemory(MessageHeader->Buffer, MessageHeader->MaximumLength);
|
|
|
|
if (KdbgNextApiNumber == DbgKdGetContextApi)
|
|
|
|
{
|
|
|
|
ManipulateState->ApiNumber = DbgKdGetContextApi;
|
|
|
|
MessageData->Length = 0;
|
|
|
|
MessageData->Buffer = (PCHAR)&KdbgContext;
|
|
|
|
return KdPacketReceived;
|
|
|
|
}
|
|
|
|
else if (KdbgNextApiNumber == DbgKdSetContextApi)
|
|
|
|
{
|
|
|
|
ManipulateState->ApiNumber = DbgKdSetContextApi;
|
|
|
|
MessageData->Length = sizeof(KdbgContext);
|
|
|
|
MessageData->Buffer = (PCHAR)&KdbgContext;
|
|
|
|
return KdPacketReceived;
|
|
|
|
}
|
|
|
|
else if (KdbgNextApiNumber != DbgKdContinueApi)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
}
|
2020-03-09 23:00:00 +00:00
|
|
|
ManipulateState->ApiNumber = DbgKdContinueApi;
|
2020-04-09 12:31:47 +00:00
|
|
|
ManipulateState->u.Continue.ContinueStatus = KdbgContinueStatus;
|
|
|
|
|
|
|
|
/* Prepare for next time */
|
|
|
|
KdbgNextApiNumber = DbgKdContinueApi;
|
|
|
|
KdbgContinueStatus = STATUS_SUCCESS;
|
|
|
|
|
2020-03-09 23:00:00 +00:00
|
|
|
return KdPacketReceived;
|
|
|
|
}
|
|
|
|
|
2020-03-07 22:33:57 +00:00
|
|
|
if (PacketType != PACKET_TYPE_KD_DEBUG_IO)
|
|
|
|
return KdPacketTimedOut;
|
|
|
|
|
|
|
|
#ifdef KDBG
|
2022-11-27 18:58:56 +00:00
|
|
|
DebugIo = (PDBGKD_DEBUG_IO)MessageHeader->Buffer;
|
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.
For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.
KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
NtSetDebugFilterState() that now comes entirely from KD64.
- Remove KD variables that are now shared with KD64.
- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().
- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.
- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
KdpPrint() worker function that correctly probes and captures its arguments.
- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
by the shared code, until KD is removed and only the KD64 version of these
functions remain.
- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
helper compatible with KD64, that is called by the KD64 implementation of
KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
debugging, the prompt will appear on both. Before that the prompt was always
being displayed on COM port even if e.g. a SCREEN-only debug session was used...
- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().
KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
before using them elsewhere.
- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).
- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 21:55:36 +00:00
|
|
|
|
2022-11-27 18:58:56 +00:00
|
|
|
/* Validate API call */
|
|
|
|
if (MessageHeader->MaximumLength != sizeof(DBGKD_DEBUG_IO))
|
|
|
|
return KdPacketNeedsResend;
|
|
|
|
if (DebugIo->ApiNumber != DbgKdGetStringApi)
|
|
|
|
return KdPacketNeedsResend;
|
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.
For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.
KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
NtSetDebugFilterState() that now comes entirely from KD64.
- Remove KD variables that are now shared with KD64.
- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().
- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.
- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
KdpPrint() worker function that correctly probes and captures its arguments.
- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
by the shared code, until KD is removed and only the KD64 version of these
functions remain.
- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
helper compatible with KD64, that is called by the KD64 implementation of
KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
debugging, the prompt will appear on both. Before that the prompt was always
being displayed on COM port even if e.g. a SCREEN-only debug session was used...
- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().
KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
before using them elsewhere.
- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).
- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 21:55:36 +00:00
|
|
|
|
2022-11-27 18:58:56 +00:00
|
|
|
/* NOTE: We cannot use directly MessageData->Buffer here as it points
|
|
|
|
* to the temporary KdpMessageBuffer scratch buffer that is being
|
|
|
|
* shared with all the possible I/O KD operations that may happen. */
|
|
|
|
ResponseString.Buffer = MessageBuffer;
|
|
|
|
ResponseString.Length = 0;
|
|
|
|
ResponseString.MaximumLength = min(sizeof(MessageBuffer),
|
|
|
|
MessageData->MaximumLength);
|
|
|
|
ResponseString.MaximumLength = min(ResponseString.MaximumLength,
|
|
|
|
DebugIo->u.GetString.LengthOfStringRead);
|
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.
For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.
KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
NtSetDebugFilterState() that now comes entirely from KD64.
- Remove KD variables that are now shared with KD64.
- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().
- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.
- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
KdpPrint() worker function that correctly probes and captures its arguments.
- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
by the shared code, until KD is removed and only the KD64 version of these
functions remain.
- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
helper compatible with KD64, that is called by the KD64 implementation of
KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
debugging, the prompt will appear on both. Before that the prompt was always
being displayed on COM port even if e.g. a SCREEN-only debug session was used...
- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().
KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
before using them elsewhere.
- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).
- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 21:55:36 +00:00
|
|
|
|
2022-11-27 18:58:56 +00:00
|
|
|
/* The prompt string has been printed by KdSendPacket; go to
|
|
|
|
* new line and print the kdb prompt -- for SYSREG2 support. */
|
2023-03-29 17:38:10 +00:00
|
|
|
KdIoPrintString("\n", 1);
|
|
|
|
KdIoPuts(KdbPromptStr.Buffer); // Alternatively, use "Input> "
|
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.
For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.
KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
NtSetDebugFilterState() that now comes entirely from KD64.
- Remove KD variables that are now shared with KD64.
- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().
- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.
- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
KdpPrint() worker function that correctly probes and captures its arguments.
- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
by the shared code, until KD is removed and only the KD64 version of these
functions remain.
- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
helper compatible with KD64, that is called by the KD64 implementation of
KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
debugging, the prompt will appear on both. Before that the prompt was always
being displayed on COM port even if e.g. a SCREEN-only debug session was used...
- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().
KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
before using them elsewhere.
- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).
- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 21:55:36 +00:00
|
|
|
|
2019-12-26 16:19:11 +00:00
|
|
|
if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
|
|
|
|
KbdDisableMouse();
|
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.
For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.
KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
NtSetDebugFilterState() that now comes entirely from KD64.
- Remove KD variables that are now shared with KD64.
- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().
- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.
- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
KdpPrint() worker function that correctly probes and captures its arguments.
- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
by the shared code, until KD is removed and only the KD64 version of these
functions remain.
- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
helper compatible with KD64, that is called by the KD64 implementation of
KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
debugging, the prompt will appear on both. Before that the prompt was always
being displayed on COM port even if e.g. a SCREEN-only debug session was used...
- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().
KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
before using them elsewhere.
- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).
- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 21:55:36 +00:00
|
|
|
|
2023-03-22 18:45:33 +00:00
|
|
|
/*
|
|
|
|
* Read a NULL-terminated line of user input and retrieve its length.
|
|
|
|
* Official documentation states that DbgPrompt() includes a terminating
|
|
|
|
* newline character but does not NULL-terminate. However, experiments
|
|
|
|
* show that this behaviour is left at the discretion of WinDbg itself.
|
|
|
|
* WinDbg NULL-terminates the string unless its buffer is too short,
|
|
|
|
* in which case the string is simply truncated without NULL-termination.
|
|
|
|
*/
|
|
|
|
ResponseString.Length =
|
2023-03-20 16:49:15 +00:00
|
|
|
(USHORT)KdIoReadLine(ResponseString.Buffer,
|
|
|
|
ResponseString.MaximumLength);
|
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.
For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.
KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
NtSetDebugFilterState() that now comes entirely from KD64.
- Remove KD variables that are now shared with KD64.
- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().
- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.
- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
KdpPrint() worker function that correctly probes and captures its arguments.
- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
by the shared code, until KD is removed and only the KD64 version of these
functions remain.
- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
helper compatible with KD64, that is called by the KD64 implementation of
KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
debugging, the prompt will appear on both. Before that the prompt was always
being displayed on COM port even if e.g. a SCREEN-only debug session was used...
- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().
KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
before using them elsewhere.
- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).
- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 21:55:36 +00:00
|
|
|
|
2019-12-26 16:19:11 +00:00
|
|
|
if (!(KdbDebugState & KD_DEBUG_KDSERIAL))
|
|
|
|
KbdEnableMouse();
|
[NTOS:KD/KD64/KDBG] Share some code between our legacy KD/KDBG and KD64.
Our legacy KD module is slowly being phased out for the more recent KD64
Kernel Debugger that supports WinDbg, but at the same time we must retain
support for GCC debugging and the KDBG interface.
For the time being few #ifdef _WINKD_ have been introduced in KD64 so that
some of its code/data does not completely get shared yet with the legacy KD,
until the latter becomes phased out.
KD Modifications:
=================
- Remove the implementation of NtQueryDebugFilterState() /
NtSetDebugFilterState() that now comes entirely from KD64.
- Remove KD variables that are now shared with KD64.
- Share common code with KD64: KdpMoveMemory(), KdpZeroMemory(),
KdpCopyMemoryChunks(), KdpPrint(), KdpPrompt().
- KDBG: Remove the duplicated KdpCopyMemoryChunks() function.
- In KdpServiceDispatcher() and KdpEnterDebuggerException(), call the
KdpPrint() worker function that correctly probes and captures its arguments.
- Temporarily stub out KdEnterDebugger() and KdExitDebugger() that is used
by the shared code, until KD is removed and only the KD64 version of these
functions remain.
- Re-implement the KD/KDBG KdpPrompt() function using a custom KdpPromptString()
helper compatible with KD64, that is called by the KD64 implementation of
KdpPrompt(). This KdpPromptString() helper now issues the prompt on all
the KD loggers: e.g. if you use both at the same time COM-port and SCREEN
debugging, the prompt will appear on both. Before that the prompt was always
being displayed on COM port even if e.g. a SCREEN-only debug session was used...
- ppc_irq.c: Fix the prototype of KdpServiceDispatcher().
KD64 Fixes:
===========
- Initialize the MaximumLength member of the counted STRING variables
before using them elsewhere.
- Get rid of alloca() within SEH block in KdpPrint() (addendum to 7b95fcf9).
- Add the ROS-specific handy dump commands in KdSystemDebugControl().
2019-11-17 21:55:36 +00:00
|
|
|
|
2023-03-22 18:45:33 +00:00
|
|
|
/* Adjust and return the string length */
|
|
|
|
*DataLength = min(ResponseString.Length + sizeof(ANSI_NULL),
|
|
|
|
DebugIo->u.GetString.LengthOfStringRead);
|
2022-11-27 18:58:56 +00:00
|
|
|
MessageData->Length = DebugIo->u.GetString.LengthOfStringRead = *DataLength;
|
|
|
|
|
|
|
|
/* Only now we can copy back the data into MessageData->Buffer */
|
|
|
|
RtlCopyMemory(MessageData->Buffer, ResponseString.Buffer, *DataLength);
|
2020-03-28 23:30:53 +00:00
|
|
|
#endif
|
2022-11-27 18:58:56 +00:00
|
|
|
|
2020-03-07 22:33:57 +00:00
|
|
|
return KdPacketReceived;
|
2020-03-07 10:39:37 +00:00
|
|
|
}
|
|
|
|
|
2005-04-25 14:44:48 +00:00
|
|
|
/* EOF */
|