Hindsight is 20/20, EvtDriverUnload should have not been in KMDF


The KMDF model evolved over the entire development cycle. It was refined and refactored multiple times. A lot of WDM abstractions leak through the to the KMDF model. These leaks usually forced their way into the model because without them, KMDF cannot function properly. Other abstraction leaks were just design decisions that were not updated or removed as KMDF evolved through its v1.0 development cycle.

One abstraction that should have been refactored away but was not is the EvtDriverUnload routine. Our initial thought was that since the KMDF driver must implement a DriverEntry routine, an optional driver unload routine should also be a part of the model. The problem is that if DriverEntry() returns !NT_SUCCESS, the WDM DriverUnload (and hence EvtDriverUnload) is not called. If you created global resources in DriverEntry and cleaned them up in (Evt)DriverUnload, they would not be cleaned up becuase the unload routine would never be called. Normally drivers do not create such global data, so we (the KMDF team) didn’t realize that this design issue was a problem.

There is an easy fix though that we have been advocating. Instead of putting your cleanup code in EvtDriverUnload, put all cleanup code in the EvtObjectCleanup routine in the object attributes for the WDFDRIVER you create when calling WdfDriverCreate(). The cleanup routine is guaranteed to be called in both cases (DriverEntry() returning NT_SUCCESS() or !NT_SUCCESS()) once the WDFDRIVER has been created successfully. Note that important restriction, WdfDriverCreate() must return success for this pattern to work! That means that the allocation and initialization of all global resources should occur after WdfDriverCreate() has been called.

In hindsight we should have never had a EvtDriverUnload and should have had the WDFDRIVER’s cleanup routine be the driver unload equivalent. Two things affected our decision to not make this change. First, we didn’t realize the pattern was busted until late in the development process. By the time we did realize it, there were too many drivers in the wild and under developement to make such a significant change. Second, while EvtDriverUnload was created when KMDF development was first started, the standardized cleanup routine for each object was not introduced until much later. If both concepts were implemented at the same time in the development cycle, the unload routine would have been eliminated

Comments (10)

  1. dispensa says:

    > Normally drivers do not create such global data, so we (the KMDF team) didn’t realize that this design issue was a problem.

    Something I’ve done in the past is to create things like lookaside lists in DriverEntry and then share them across lots of devices – minor space and perf improvement sometimes.

    The exception may prove the rule, of course.

  2. It’s a good pattern if you have fixed sizes across multiple devices.  I’ve done the same thing in a few WDM drivers, but when we ported the KMDF samples from WDM, none of them had global data.  It is a valid pattern, we just realized its semantics too late 🙁

  3. Windhunter says:

    Hello.

    I’m writing KMDF driver for USB. I’ve tested speed. But maximum, I’ve reached, was about 8 MB/s. I used some code from sample and worked with one of Cypress’s chips (pipe – interrupt, 1024). I wonder, am I missing something in the code or is KMDF really slower than WDM?

    NTSTATUS

    ConfigContReaderForInterruptEndPoint(PDEVICE_CONTEXT DeviceContext)

    {

    WDF_USB_CONTINUOUS_READER_CONFIG contReaderConfig;

    NTSTATUS status;

    WDF_USB_CONTINUOUS_READER_CONFIG_INIT(&contReaderConfig,

    EvtUsbInterruptPipeReadComplete,

    DeviceContext,    // Context

    1024);   // TransferLength

    contReaderConfig.NumPendingReads = 4;//Is it maximum possible value?

    status = WdfUsbTargetPipeConfigContinuousReader(DeviceContext->InterruptPipe,

    &contReaderConfig);

    KdPrint(("Interrupt pipe has been configuredn"));

    if (!NT_SUCCESS(status))

    {

    KdPrint(("ConfigContReaderForInterruptEndPoint failed %xn", status));

    return status;

    }

    return status;

    }

    VOID

    EvtUsbInterruptPipeReadComplete(WDFUSBPIPE  Pipe,

    WDFMEMORY   Buffer,

    size_t      NumBytesTransferred,

    WDFCONTEXT  Context)

    {

    PUCHAR          switchState = NULL;

    WDFDEVICE       device;

    PDEVICE_CONTEXT pDeviceContext = (PDEVICE_CONTEXT)Context;

    UNREFERENCED_PARAMETER(Pipe);

    WdfObjectContextGetObject((PVOID)pDeviceContext);

    pDeviceContext->Count++;

    if(pDeviceContext->Count == 10000)

    {

    KdPrint(("10 Mb has been recieved! n"));

    pDeviceContext->Count = 0;

    }

    }

  4. boeysue says:

    Help for BDA with Wdm lower-edge (USB) in KMDF!

    Is there any unload api in kmdf?

    In Ndis ,it seems to be WdfMiniportUnload.

    But in BDA,should we just simply killed WDFDriver framework object?

    Or Is there any sample that we can follow to pass the test in WDF?

  5. if you specified WdfDriverInitNoDispatchOverride in your WDF_DRIVER_CONFIG, then you must call WdfMiniportUnload in your DriverUnload routine (just like the NDIS sample)

    d

  6. boeysue says:

    Sorry, Does It means the BDA driver is miniport driver?

    And where should I call WdfMiniportUnload in BDA?

    In the BDA descript object model,there seems to be no unload callback function. There is just a stop callback function.Should I call WdfMiniportUnload in there?

    Best Regards.

  7. Having never written a BDA driver, i looked it up on MSDN.  It looks lie you are a special type of KS driver which has to call KsInitializeDriver, http://msdn.microsoft.com/library/default.asp?url=/library/en-us/stream_d/hh/Stream_d/bdadg_6587a790-f8ed-4fd0-bec6-02d7f128dfd1.xml.asp.  It does not look like the KSDEVICE_DESCRIPTOR has an Unload routine. To fix this you can call KsInitializeDriver and when it returns success, capture the unload routine (if one is set) and replace it with your own, something like this

    PDRIVER_UNLOAD KsUnload = NULL; // global variable

    NTSTATUS DriverEntry(…)

    {

       NTSTATUS status = KsInitializeDriver(…);o

       if (NT_SUCCESS(status)) {

          KsUnload = DriverObject->DriverUnload;

          DriverObject->DriverUnload = MyUnload;

      }

      ….initialize KMDF…

      return status;

    }

    void MyUnload(PDRIVER_OBJECT Driver)

    {

       if (KsUnload != NULL) { KsUnload(Driver); }

       WdfMiniportUnload(WdfGetDriver());

    }

  8. boeysue says:

    Sorry,But use these example ,KMDF is not loaded.

    Can it pass the WDF signature verify test?

    Should I add WDFDriverCreate in DriverEntry?

    And another question is WdfMiniportUnload is for NDis or for all mini-class driver?

    Is it useful for BDA driver?

    Thanks for help.

  9. > Sorry,But use these example ,KMDF is not loaded.

    That is because we didn’t write a BDA or KS KMDF sample, it is up to those teams to write such a sample.  it is your job as a developer to extrapolate from one sample and it apply it to your task.

    > Can it pass the WDF signature verify test?

    There is no such test.  There are certain classes (NDIS-WDM, input) which require KMDF, but we only test that you are using KMDF, not that *how* you are using KMDF

    > Should I add WDFDriverCreate in DriverEntry?

    yes, just like the NDIS-WDM sample.

    >And another question is WdfMiniportUnload is for NDis or for all mini-class driver?

    WdfMiniportUnload is applicable to any situation where you are creating a WDFDRIVER with the WdfDriverInitNoDispatchOverride flag, see the topic "Using Kernel-Mode Driver Framework with Miniport Drivers", http://msdn.microsoft.com/library/default.asp?url=/library/en-us/kmdf_d/hh/KMDF_d/Ch8_DFTechniques_9af1406b-2188-47ac-bc5b-f03fbaa786be.xml.asp

    > Is it useful for BDA driver?

    As much as it is useful in an NDIS WDM driver.  in this mode KMDF will allow you to use the DMA and USB related objects, so if you want to use KMDF to manage your USB I/O, this will work.  you do not get to use WDFQUEUE or any of the pnp or power management features of KMDF (KS takes care of that for you).

    d

  10. One thing that is easily overlooked about implementing DriverEntry is that upon return !NT_SUCCESS, DriverUnload