DEV Community

Deleon Karen
Deleon Karen

Posted on

Part 2: Driver Entry and Device Initialization

In the lifecycle of a WDDM driver, the initialization phase establishes the "contractual" relationship between the driver and the operating system. This chapter will provide an in-depth analysis of every core step from driver loading to device readiness, from the perspective of the underlying DDI.

1. The Soul of the Driver: Deep Dive into the DriverEntry Protocol

DriverEntry is the entry point for a KMD. Its core task is to register a set of callback function tables with Dxgkrnl via DxgkInitialize.

1.1 Core Structure: DRIVER_INITIALIZATION_DATA

This structure is very large, containing hundreds of callback interfaces. In practical engineering, you need to focus on the following points:

  • Version Control (Version): Must be set to DXGKDDI_INTERFACE_VERSION. This macro is defined differently across WDK versions, directly determining which DDIs the OS will attempt to call.
  • Mandatory Interfaces: If you omit core functions like DxgkDdiAddDevice, DxgkDdiStartDevice, or DxgkDdiExchangePnPInterface, DxgkInitialize will directly return STATUS_INVALID_PARAMETER.

1.2 Registration Example

// Example: Registering basic DDIs at the entry point
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
    DRIVER_INITIALIZATION_DATA initData = {0};
    initData.Version = DXGKDDI_INTERFACE_VERSION;

    // Basic Lifecycle
    initData.DxgkDdiAddDevice = MyAddDevice;
    initData.DxgkDdiStartDevice = MyStartDevice;
    initData.DxgkDdiStopDevice = MyStopDevice;
    initData.DxgkDdiRemoveDevice = MyRemoveDevice;
    initData.DxgkDdiUnload = MyUnload;

    // Core Management
    initData.DxgkDdiQueryAdapterInfo = MyQueryAdapterInfo;
    initData.DxgkDdiCreateDevice = MyCreateDevice;
    initData.DxgkDdiDestroyDevice = MyDestroyDevice;

    // Memory and Scheduling (Basic Set)
    initData.DxgkDdiCreateAllocation = MyCreateAllocation;
    initData.DxgkDdiDestroyAllocation = MyDestroyAllocation;
    initData.DxgkDdiBuildPagingBuffer = MyBuildPagingBuffer;
    initData.DxgkDdiSubmitCommand = MySubmitCommand;

    return DxgkInitialize(DriverObject, RegistryPath, &initData);
}
Enter fullscreen mode Exit fullscreen mode

1.3 Special Case: Display-Only Driver (KMDOD)

For drivers without rendering capabilities that only support display (Kernel-Mode Display-Only Driver), the flow is slightly different:

  • Uses the KMDDOD_INITIALIZATION_DATA structure.
  • Registers via DxgkInitializeDisplayOnlyDriver.
  • Typically used for basic display adapters or remote desktop display drivers.

2. Establishing Context: DxgkDdiAddDevice

When the PnP Manager discovers hardware, the OS calls AddDevice once for each physical adapter.

2.1 Core Tasks

  • Miniport Device Context: You need to allocate a driver-private device context (usually a structure) here and return it to the OS. All subsequent device-related DDIs will carry this pointer.
  • Obtaining Hardware Information: You should call DxgkCbGetDeviceInformation at this point. It returns a DXGK_DEVICEINFO structure containing:
    • PCI Configuration Space Information.
    • Translated Resource List: Including physical memory base addresses (BARs) and interrupt vectors.

2.2 Registering Hardware Information (Registry Practice)

According to official specifications, to correctly identify the hardware in "Control Panel -> Display", the driver must set the following registry values in AddDevice:

Information Type Registry Key Name Description
Chip Type HardwareInformation.ChipType Friendly name string for the chip
DAC Type HardwareInformation.DacType DAC type identifier
Memory Size HardwareInformation.MemorySize ULONG, unit in MB
Adapter Name HardwareInformation.AdapterString Full name of the adapter
BIOS Info HardwareInformation.BiosString BIOS version string

Implementation Hint: Use IoOpenDeviceRegistryKey to open the PLUGPLAY_REGKEY_DRIVER key, then use ZwSetValueKey to write the above values.

3. "Ignition" Execution: DxgkDdiStartDevice

StartDevice signals that the hardware should begin actual operation.

  • Dxgkrnl Interface Exchange: The OS passes in the DXGKRNL_INTERFACE. This interface contains all DxgkCbXxx callbacks (e.g., querying VidPN, notifying interrupts). The driver must save this pointer.
  • Hardware Resource Initialization: Map MMIO registers, initialize GPU core logic.
  • Preliminary Capability Report:
    • NumberOfChildren: Reports the number of devices connected downstream of the display adapter (e.g., HDMI ports, internal panels).
    • NumberOfVideoPresentSources: Reports the number of display controllers inside the GPU (determines how many independent screens can be driven simultaneously).

4. Deep Dive: The Information Storm of DxgkDdiQueryAdapterInfo

This is the busiest DDI during initialization. The OS queries various configurations using different Type values.

  • DXGKQAITYPE_DRIVERCAPS:
    • Core Flags: SupportGpuVirtualAddress (whether virtual addresses are supported), CanHandleTDR (whether timeout recovery is supported).
    • Scheduling Policy: Determines whether global scheduling or hardware scheduling is used.
  • DXGKQAITYPE_QUERYSEGMENT:
    • Defines Memory Topology: Tells the OS which segments are local video memory (VRAM) and which are system memory apertures.
    • Segment Properties: The Aperture flag determines how VidMm handles that memory.
  • DXGKQAITYPE_UMDRIVERPRIVATE:
    • UMD Path: Returns the file path of the UMD DLL (e.g., my_umd.dll). The OS uses this name to load the user-mode component.

5. Practical Engineering: The State Machine of the Initialization Phase

Understanding the calling sequence of these DDIs is critical for troubleshooting startup failures. The following is the deep call flow organized according to the WDDM specification:

Key Steps Explained:

  1. DxgkDdiStartDevice: Must accurately return NumberOfChildren (e.g., number of HDMI, DP ports) and NumberOfVideoPresentSources (number of CRTCs inside the GPU).
  2. DxgkDdiQueryChildRelations: The driver needs to fill in ChildUid here. This ID will be used as VideoPresentTargetId in subsequent VidPN management.
  3. HPD (Hot Plug Detection): For interfaces with interrupt or polling capabilities, the OS confirms if a monitor is currently connected via QueryChildStatus.
  4. VidPN Negotiation: This is the most complex part of initialization, involving the VidPN Manager cooperating with the driver to establish the initial display path (Source -> Target).

6. Expert Recommendations

  • Lazy Initialization: Avoid time-consuming hardware detection in AddDevice as much as possible to keep the PnP process smooth.
  • Strict Version Checking: In QueryAdapterInfo, if a feature requested by the OS is completely unsupported by your hardware, directly return STATUS_NOT_SUPPORTED.
  • Error Cleanup: If StartDevice fails, be sure to manually clean up already allocated resources and MMIO mappings before returning. The OS will not automatically roll back memory allocated in AddDevice.

Top comments (0)