Techwiki:Kd
Contents
The Kernel Debugging Protocol
The Kernel Debugging (KD) protocol is a low-level interface used by the kernel and the kernel debugger for hardware-independent communication[1][2][3]. It hides the hardware-specific implementation of port communication and presents a uniform API for all types of ports.
This API is implemented in a separate DLL and there is one DLL for each type of port. The KD DLL is given full control of the debug port. No one else is allowed to use it.
KD DLL file | Port | Windows version |
---|---|---|
kdcom.dll | COM | NT 5.1 (XP) and later |
kd1394.dll | FireWire IEEE 1394 | NT 5.1 (XP) and later |
kdusb.dll | USB 2.0 | NT 6.0 (Vista) and 6.1 (Windows 7) |
USB 3.0 xHCI | NT 6.2 (Windows 8) and later | |
kdnet.dll | Ethernet (Network) | NT 6.2 (Windows 8) and later |
kd.dll | Local Kernel Debugger[4] | NT 6.2 (Windows 8) and later |
A well-known 3rd-party KD DLL is kdbazis.dll
from VirtualKD[5], used to speed up kernel debugging of a Windows instance virtualized in either VirtualBox or VMWare, using WinDbg running on the host computer.
Initialization
KD initialization takes place early during boot, meaning the kernel debugger can connect early and troubleshoot boot issues. The KD DLL is responsible for reading command line settings[6], performing hardware-specific initialization, and everything else required to set up the debug port. All of this is specific to the type of port used.
If the port is successfully initialized, STATUS_SUCCESS
is returned.
If initialization failed, an appropriate error status is returned.
The kernel responds to failure by disabling the debugger.
Windows XP/2003 to Windows 8.1
NTSTATUS
NTAPI
KdDebuggerInitialize0(
_In_opt_ PLOADER_PARAMETER_BLOCK LoaderBlock
);
This API is used to perform early initialization in phase 0, when the system is in a state transition (very early at boot initialization time or resuming from hibernation, when the debugger is being re-enabled, or when the system is in an "unstable" state (BSoD)). Early initialization usually consists of reading command line parameters from the loader block and initializing the port itself. If no loader block is provided, or if no settings are specified or are incorrect (wrong syntax), then default settings are used. If the settings are theoretically correct, but are actually wrong (e.g. non-existing port, unsupported COM port baudrate, ...) an error code is returned.
This function is invoked only when the debugger is being enabled, by nt!KdInitSystem(0, ...)
:
- at system startup, with
nt!KdInitSystem(0, LoaderBlock)
; - when resuming from hibernation, with
nt!KdInitSystem(0, NULL)
; - when enabling the debugger via
KdEnableDebugger()
(ornt!KdEnableDebuggerWithLock
), withnt!KdInitSystem(0, NULL)
; - or when a BSoD happens, with
nt!KdInitSystem(0, NULL)
.
NTSTATUS
NTAPI
KdDebuggerInitialize1(
_In_opt_ PLOADER_PARAMETER_BLOCK LoaderBlock
);
This API is used to perform initialization which could not be done during phase 0, and that needs to be done after the kernel executive services (in particular, the memory manager and registry) are available. Again, if no loader block is provided, default settings are used.
This function is always invoked (whether the debugger is active or disabled) during phase 1 initialization of the kernel executive, by nt!Phase1InitializationDiscard
.
Windows 10+
On Windows 10 and later versions, both these two functions have been deprecated and replaced by one single KdInitialize
API.
NTSTATUS
NTAPI
KdInitialize(
_In_ ULONG Phase,
_Inout_opt_ PVOID Buffer,
_Inout_ PKD_CONTEXT Context
);
Phase
0
:KdDebuggerInitialize0(LoaderBlock);
is replaced byKdInitialize(0, LoaderBlock, &KdpContext);
.1
:KdDebuggerInitialize1(LoaderBlock);
is replaced byKdInitialize(1, LoaderBlock, &KdpContext);
.
New phases:
2
: Invoked withBuffer == NULL
bynt!IoInitSystemPreDrivers
, before all drivers get loaded.3
: Invoked withBuffer
pointing to aULONGLONG
buffer retrieving data, bynt!NtSetSystemInformation(InfoClass, ...)
whenInfoClass == SystemVmGenerationCountInformation (0xA1)
.4
: Invoked withBuffer == NULL
andContext == NULL
bynt!HalpAcpiPostSleep
.
Packet Communication
The most interesting part! Much to do!
A KD DLL exports 2 functions for communication across the debug port. What each function does vary greatly depending on the type of packet.
VOID
NTAPI
KdSendPacket(
_In_ ULONG PacketType,
_In_ PSTRING MessageHeader,
_In_opt_ PSTRING MessageData,
_Inout_ PKD_CONTEXT Context
);
Sends a packet through the debug port.
KDSTATUS
NTAPI
KdReceivePacket(
_In_ ULONG PacketType,
_Out_ PSTRING MessageHeader,
_Out_ PSTRING MessageData,
_Out_ PULONG DataLength,
_Inout_ PKD_CONTEXT Context
);
Receives a packet from the debug port.
typedef enum _KDSTATUS
{
KdPacketReceived,
KdPacketTimedOut,
KdPacketNeedsResend
} KDSTATUS;
typedef struct _STRING
{
USHORT Length;
USHORT MaximumLength;
PCHAR Buffer;
} STRING, *PSTRING;
The buffer can be one of many types of structures, depending on the type of packet. These structures in turn contain nested unions and even more flags, making a large number of possible structures.
typedef struct _KD_CONTEXT
{
ULONG KdpDefaultRetries;
BOOLEAN KdpControlCPending;
} KD_CONTEXT, *PKD_CONTEXT;
State Saving and Restoring (Deprecated in Windows 10+)
The following exported routines can be used by the KD DLL to save and restore the state of the debug port it manages, during processor context switches made by the kernel debugger, or just before machine ACPI sleep/wakeup transition by the HAL.
If they are unused, the KD DLL usually returns STATUS_SUCCESS
.
NTSTATUS
NTAPI
KdSave(
_In_ BOOLEAN SleepTransition
);
Saves the debug port state before undergoing a transition.
SleepTransition
If TRUE
, this is a sleep transition.
If FALSE
, this is a KD-induced processor context switch transition.
NTSTATUS
NTAPI
KdRestore(
_In_ BOOLEAN SleepTransition
);
Restores the debug port state after undergoing a transition.
SleepTransition
If TRUE
, this is a sleep transition.
If FALSE
, this is a KD-induced processor context switch transition.
Power State Control
Because the KD DLL is fully responsible for the debug port, it must take care of the port's power state by itself.
These APIs are invoked whenever a module (the kernel itself, the HAL, ...) invokes the kernel-exported KdPowerTransition(DEVICE_POWER_STATE)
routine.
If they are unused, the KD DLL usually returns STATUS_SUCCESS
.
Windows XP/2003 to Windows 8.1
NTSTATUS
NTAPI
KdD0Transition(VOID);
Causes the debug port to undergo a D0 (fully on) transition.
NTSTATUS
NTAPI
KdD3Transition(VOID);
Causes the debug port to undergo a D3 (fully off) transition.
Windows 10+
On Windows 10 and later versions, these two functions, as well as KdSave
and KdRestore
(see previous section), have been deprecated and replaced by one single KdPower
API.
NTSTATUS
NTAPI
KdPower(
_In_ ULONG State,
_Inout_ PKD_CONTEXT Context
);
Hibernation support (Windows 8+)
Windows 8 and later introduced a specific API for the KD DLL to support hibernation.
It is invoked before hibernation by the system for marking the code in the KD DLL, so that it can be properly handled during hibernation and resume from hibernation.
(This routine typically calls PoSetHiberRange()
[7].)
- Windows 8/8.1 definition:
VOID
NTAPI
KdSetHiberRange(VOID);
- Windows 10+ definition:
VOID
NTAPI
KdSetHiberRange(
_Inout_ PKD_CONTEXT Context
);
References
- ↑ KD extension DLLs & KDCOM protocol (SysProgs)
- ↑ Fast kernel debugging for VMware, part 1: Overview
- ↑ Fast kernel debugging for VMware, part 2: KD Transport Module Interface
- ↑ It's not clear yet why this DLL is required, while it was not needed in prior Windows versions to perform local debugging.
- ↑ SysProgs VirtualKD
- ↑ The command line syntax is specified on MSDN: https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/switch-options-for-boot-files
- ↑ https://learn.microsoft.com/en-us/windows-hardware/drivers/debugger/how-to-develop-kdnet-extensibility-modules#additional-routines