Techwiki:Kd

From ReactOS Wiki
Jump to: navigation, search

Techwiki:Main

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.

Typical Microsoft KD DLLs available and their corresponding ports
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() (or nt!KdEnableDebuggerWithLock), with nt!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 by KdInitialize(0, LoaderBlock, &KdpContext);.
  • 1: KdDebuggerInitialize1(LoaderBlock); is replaced by KdInitialize(1, LoaderBlock, &KdpContext);.

New phases:

  • 2: Invoked with Buffer == NULL by nt!IoInitSystemPreDrivers, before all drivers get loaded.
  • 3: Invoked with Buffer pointing to a ULONGLONG buffer retrieving data, by nt!NtSetSystemInformation(InfoClass, ...) when InfoClass == SystemVmGenerationCountInformation (0xA1).
  • 4: Invoked with Buffer == NULL and Context == NULL by nt!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

Techwiki:Main