1 / 44

Using the Windows Driver Framework to build better drivers

HW-328T. Using the Windows Driver Framework to build better drivers. Peter Wieland WDF Team Technical Lead Microsoft Corporation. Agenda. Types of drivers in Windows Challenges to writing a quality d river How the Windows driver framework (WDF) helps Takeaways

abiola
Download Presentation

Using the Windows Driver Framework to build better drivers

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. HW-328T Using the Windows Driver Framework to build better drivers Peter Wieland WDF Team Technical Lead Microsoft Corporation

  2. Agenda • Types of drivers in Windows • Challenges to writing a quality driver • How the Windows driver framework (WDF) helps • Takeaways • Know how the WDF will help you deliver a great driver for a great customer experience

  3. Your customers won’t notice a great device driver • ,but they’ll certainly notice if it isn’t.

  4. Types of driver models Full Driver Mini Driver Driver Code I/O Handling Power Plug & Play Boilerplate I/O Handling Boilerplate Microsoft Code Programming Device Programming Device Talking to HW Talking to HW Miniport Driver Class Driver Power Plug & Play I/O Handling Power I/O Handling Power Plug & Play Boilerplate Plug & Play Boilerplate Programming Device Programming Device Talking to HW Talking to HW

  5. Anatomy of a full Windows driver Windows Driver Model (WDM) Driver Code Microsoft Code I/O Handling Power Plug & Play Boilerplate Driver Programming Device Talking to Hardware Hardware (or another driver)

  6. Anatomy of a WDF driver Windows Driver Model (WDM) Driver Code Microsoft Code I/O Handling Power Plug & Play Boilerplate Driver Programming Device Talking to Hardware Hardware (or another driver)

  7. WDF for kernel mode drivers • Kernel Mode Framework (KMDF) provides • Composablebuilding blocks • Default behaviors • Consistent interfaces & development patterns • Start simple, opt into complexity as required • WDF doesn’t wrap everything • Interfaces focus on common driver scenarios • Can escape to WDM if needed

  8. WDF for user mode drivers User Mode Host • User Mode Framework (UMDF) is most of KMDF but in user-mode • Simpler, more familiar development environment for new driver developers • User is isolated from driver crashes or security breaches • Developer is isolated from crashes too • Supported for many peripheral devices I/O Handling Power Plug & Play Device Specific Code (i.e. Driver) Talking to Hardware Kernel WDM Hardware

  9. A simple little driver

  10. Simple little driver • Fully functional driver • Could install this on any USB device • Full Plug & Play support • Full power management • Written using KMDF

  11. SimpleLittleDriver.sys • #include <wdk.h> • #include <wdf.h> • DRIVER_INITIALIZE DriverEntry; • EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; • NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, • PUNICODE_STRING RegistryPath) { • WDF_DRIVER_CONFIG config; • WDF_DRIVER_CONFIG_INIT(&config, OnDeviceAdd); • return WdfDriverCreate(DriverObject, • RegistryPath, • WDF_NO_OBJECT_ATTRIBUTES, • &config, • WDF_NO_HANDLE); • } • NTSTATUS OnDeviceAdd(WDFDRIVER Driver, • PWDFDEVICE_INIT DeviceInit) { • return WdfDeviceCreate(&DeviceInit, • WDF_NO_OBJECT_ATTRIBUTES, • WDF_NO_HANDLE); • }

  12. SimpleLittleDriver.sys • #include <wdk.h> • #include <wdf.h> • DRIVER_INITIALIZE DriverEntry; • EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; • NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, • PUNICODE_STRING RegistryPath) { • WDF_DRIVER_CONFIG config; • WDF_DRIVER_CONFIG_INIT(&config, OnDeviceAdd); • return WdfDriverCreate(DriverObject, • RegistryPath, • WDF_NO_OBJECT_ATTRIBUTES, • &config, • WDF_NO_HANDLE); • } • NTSTATUS OnDeviceAdd(WDFDRIVER Driver, • PWDFDEVICE_INIT DeviceInit) { • return WdfDeviceCreate(&DeviceInit, • WDF_NO_OBJECT_ATTRIBUTES, • WDF_NO_HANDLE); • } Called when driver loads

  13. SimpleLittleDriver.sys • #include <wdk.h> • #include <wdf.h> • DRIVER_INITIALIZE DriverEntry; • EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; • NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, • PUNICODE_STRING RegistryPath) { • WDF_DRIVER_CONFIG config; • WDF_DRIVER_CONFIG_INIT(&config, OnDeviceAdd); • return WdfDriverCreate(DriverObject, • RegistryPath, • WDF_NO_OBJECT_ATTRIBUTES, • &config, • WDF_NO_HANDLE); • } • NTSTATUS OnDeviceAdd(WDFDRIVER Driver, • PWDFDEVICE_INIT DeviceInit) { • return WdfDeviceCreate(&DeviceInit, • WDF_NO_OBJECT_ATTRIBUTES, • WDF_NO_HANDLE); • } Callback for when driver is attached to a device

  14. SimpleLittleDriver.sys • #include <wdk.h> • #include <wdf.h> • DRIVER_INITIALIZE DriverEntry; • EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; • NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, • PUNICODE_STRING RegistryPath) { • WDF_DRIVER_CONFIG config; • WDF_DRIVER_CONFIG_INIT(&config, OnDeviceAdd); • return WdfDriverCreate(DriverObject, • RegistryPath, • WDF_NO_OBJECT_ATTRIBUTES, • &config, • WDF_NO_HANDLE); • } • NTSTATUS OnDeviceAdd(WDFDRIVER Driver, • PWDFDEVICE_INIT DeviceInit) { • return WdfDeviceCreate(&DeviceInit, • WDF_NO_OBJECT_ATTRIBUTES, • WDF_NO_HANDLE); • } Use configuration to make a “driver object”

  15. SimpleLittleDriver.sys • #include <wdk.h> • #include <wdf.h> • DRIVER_INITIALIZE DriverEntry; • EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; • NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, • PUNICODE_STRING RegistryPath) { • WDF_DRIVER_CONFIG config; • WDF_DRIVER_CONFIG_INIT(&config, OnDeviceAdd); • return WdfDriverCreate(DriverObject, • RegistryPath, • WDF_NO_OBJECT_ATTRIBUTES, • &config, • WDF_NO_HANDLE); • } • NTSTATUS OnDeviceAdd(WDFDRIVER Driver, • PWDFDEVICE_INIT DeviceInit) { • return WdfDeviceCreate(&DeviceInit, • WDF_NO_OBJECT_ATTRIBUTES, • WDF_NO_HANDLE); • } Callback when Windows assigns the driver to a device

  16. SimpleLittleDriver.sys • #include <wdk.h> • #include <wdf.h> • DRIVER_INITIALIZE DriverEntry; • EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; • NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, • PUNICODE_STRING RegistryPath) { • WDF_DRIVER_CONFIG config; • WDF_DRIVER_CONFIG_INIT(&config, OnDeviceAdd); • return WdfDriverCreate(DriverObject, • RegistryPath, • WDF_NO_OBJECT_ATTRIBUTES, • &config, • WDF_NO_HANDLE); • } • NTSTATUS OnDeviceAdd(WDFDRIVER Driver, • PWDFDEVICE_INIT DeviceInit) { • return WdfDeviceCreate(&DeviceInit, • WDF_NO_OBJECT_ATTRIBUTES, • WDF_NO_HANDLE); • } Create a “Device Object” for this driver and add it to the driver stack

  17. SimpleLittleDriver.sys • #include <wdk.h> • #include <wdf.h> • DRIVER_INITIALIZE DriverEntry; • EVT_WDF_DRIVER_DEVICE_ADD OnDeviceAdd; • NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, • PUNICODE_STRING RegistryPath) { • WDF_DRIVER_CONFIG config; • WDF_DRIVER_CONFIG_INIT(&config, OnDeviceAdd); • return WdfDriverCreate(DriverObject, • RegistryPath, • WDF_NO_OBJECT_ATTRIBUTES, • &config, • WDF_NO_HANDLE); • } • NTSTATUS OnDeviceAdd(WDFDRIVER Driver, • PWDFDEVICE_INIT DeviceInit) { • return WdfDeviceCreate(&DeviceInit, • WDF_NO_OBJECT_ATTRIBUTES, • WDF_NO_HANDLE); • } • Less than 25 lines of code • Minimal boilerplate • Minimal cleanup code

  18. Storing Driver Specific Data

  19. Tracking memory use • Drivers are very dynamic, lots of state to track & cleanup • State of device, client requests, background work, etc… • Error handling adds to clean-up work • Becomes difficult to keep up with • Drivers share address space • Proper management is critical • WDF automates much of this through objects

  20. WDF objects • WDF objects help driver manage its state & allocations • WDF objects make up the WDF API • WDF knows the lifetime of many objects, deletes automatically • Object context • Space for driver to store its own data • Freed with the object • Object events to help with clean-up • Object parents & children • Can override default object parent • Deleting an object deletes the children

  21. Adding Driver’s State & Data • structDeviceContext { • MYDEVICE_STATE CurrentState; • ... • }; • WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(DeviceContext, • GetDeviceContext); • NTSTATUS OnDeviceAdd(...) { • WDFDEVICE device; • DeviceContext* context; • WDF_OBJECT_ATTRIBUTES attributes; • WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, • DeviceContext); • attributes.EvtDestroyCallback= OnDeviceDestroy; • WdfDeviceCreate(&DeviceInit, &attributes, &device); • if (failure) {return status;} • deviceContext = GetDeviceContext(device); • deviceContext->CurrentState = MyDeviceStateUninitialized; • ... • } • Set a callback to free memory allocated for the device • Declare the structure to be an object context type. GetDeviceContext will get it from the object • Get the context off the new object & initialize it • Initialize object attributes structure with the new context type • Supply object attributes when creating device • Define a structure to hold driver’s private data for the Device

  22. Creating Child Objects • NTSTATUS OnDeviceAdd(...) { • WdfUsbTargetCreate(device, • WDF_NO_OBJECT_ATTRIBUTES, • &deviceContext->UsbIoTarget); • if (failure) return status; • WDF_OBJECT_ATTRIBUTES attributes; • WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, • RequestContext); • attributes.ParentObject = deviceContext->UsbIoTarget; • WdfRequestCreate(&attributes, • deviceContext->UsbIoTarget, • &deviceContext->UsbRequest); • if (failure) return status; • InitializeRequestContext(deviceContext->UsbRequest); • if (failure) return status; • ... • } • WDF deletes Driver and Device Objects automatically on failure or during removal/unload • Which deletes the USB Target • Which deletes the Request • Make a Request as a child of the USB Target • Create Request • Make a USB Target as a child of the device (default parent)

  23. Handling I/O

  24. Handling I/O operations • Clients can open SimpleLittleDriver but can’t send I/O • SimpleLittleDriver doesn’t register any I/O handlers • Challenges for I/O handling are: • Asynchronous execution • Concurrency • Validation • Cancellation • Clean-up • WDF drivers handle I/O with queue and request objects

  25. I/O queues • Queues coordinate flow of requests within the driver • Driver can use multiple queues to collect or distribute work • Can dispatch requests one at a time or in parallel • WDF presents all I/O through the top level queues • Can use queues as gates to stop and restart I/O flow

  26. Request objects • Packets of work from a client • Packets support asynchronous I/O • Driver can add context/children to track state & clean-up • Simplify validation of parameters/payload • Help manage race conditions between delivery, cancellation & completion

  27. Dispatch requests one at a time • Make this the device’s default Queue • Creating an I/O Queue starts with the Object configuration Registering an I/O Callback • NTSTATUS OnDeviceAdd(…, PWDFDEVICE_INIT DeviceInit) { • ... • // After creating the device… • WDF_IO_QUEUE_CONFIG queueConfig; • WDF_IO_QUEUE_CONFIG_INIT_DEFAULT_QUEUE( • &queueConfig, • WdfIoQueueDispatchSequential • ); • queueConfig.EvtIoDeviceControl = OnDeviceControl; • WdfIoQueueCreate(device, • &queueConfig, • WDF_NO_OBJECT_ATTRIBUTES, • WDF_NO_OBJECT); • … • } • Add handler for device control Requests • Create the Queue (child of Device)

  28. Complete the request on any errors. Request completion will trigger deletion. Device Control Handler • VOID OnDeviceControl(WDFQUEUE Queue, WDFREQUEST Request, • size_tInputCb, size_tOutputCb, • ULONG IoControlCode) { • if (IoControlCode != IOCTL_MYDRIVER_DO_SOMETHING) { • goto error; • } • WdfRequestRetrieveInputBuffer(Request, • sizeof(DO_SOMETHING_INPUT), • &input, • NULL); • if (failure) goto error; • // Validate input structure • if (failure) goto error; • // Start request running. • if (failure) goto error; • return; • Error: • WdfRequestComplete(Request, status); • return; • Get the input buffer, which contains parameters from the client • Require input to be at least this size (simplifies validation) • Make sure all the input parameters are valid. • Kick off the request processing asynchronously (for very short requests, work can be done synchronously) • Return the thread to the client. Some async callback later will trigger request completion. • Device only supports one IOCTL • Handler for a device-specific operation (aka I/O control or IOCTL)

  29. Handling concurrency • Use queues to serialize requests • Use parallel queues to distribute work to sub-queues • Use sequential/manual queues to collect work & protect shared resources (hardware, data, etc…) • Use locks to coordinate between I/O and other work • WaitLock or SpinLock Objects, or WdfObjectLockmethod • Limit blocking (including locks) in I/O paths • Ties up client’s threads & increases system latency

  30. Power Management

  31. Saving power • Power management is critical for that great user experience • Windows rules for power are very complicated • Must be coordinated with PnP and asynchronous I/O • Many drivers do it wrong • Don’t power off when they aren’t in use, or • Don’t handle all the edge cases or concurrency • 10% of all driver crashes are related to power management

  32. Enabling power management • When creating a device, WDF driver • Declares device’s power capabilities • Sets power event callbacks • WDF’s power state machines control power automatically • Handles OS power change requests • Calls driver to perform device-specific power actions • Power on, power off, arm for wake, etc…

  33. Detecting need for power • Driver can set queue’s PowerManaged attribute • Power-managed queues coordinate I/O and power for you • Holds requests until device is on • Starts power up sequence when new requests arrive • Use power managed queues when you touch hardware

  34. Automatic idle detection • WDF can turn off idle devices automatically • Driver sets S0-Idle settings on device • Power state to enter • Timeout • Wake capability • System vs. driver managed transitions • Device is idle when all power managed queues are idle • Driver can stop and restart idle detection • To stay on when doing non request based work

  35. Power Callbacks & Idle Settings • NTSTATUS OnDeviceAdd(...) { • … • WDF_PNPPOWER_EVENT_CALLBACKS powerCb; • WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&powerCb); • powerCb.EvtDeviceD0Entry = OnD0Entry; • powerCb.EvtDeviceD0Exit = OnD0Exit; • WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, • &powerCb); • // create the device ... • WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS idleSettings; • WDF_DEVICE_POWER_POLICY_IDLE_SETTINGS_INIT( • &idleSettings, • IdleUsbSelectiveSuspend • ); • idleSettings.IdleTimeout = 500; // milliseconds • WdfDeviceAssignS0IdleSettings(device, &idleSettings); • if (failure) return status; • } • After creating the device, setup the idle policy using USB selective suspend to wake (since this is a pretend USB devcice) • Setup behavior of device when idle in system working state (S0) • Driver can override WDF’s default timeout • Set power callbacks before creating the Device • OnD0Entry will turn the device on, restore any volatile settings • Driver can set PnP/Power callbacks to customize device startup, shutdown & power behaviors • OnD0Exit saves the current state of the device and turns it off

  36. Summary

  37. Windows driver frameworks • WDF lets you focus on controlling your device, not dealing with the OS • KMDF can significantly reduce driver size and complexity • UMDF provide a more familiar development environment • Both let you build a high-quality driver quickly

  38. What type of driver do I need? • Use Windows class drivers where possible • Follow driver model for your device class • Use WDF’s support objects in “miniport mode” as-needed • For full drivers, use UMDF where possible • Use KMDF everywhere else • You should never have to write a WDM driver

  39. Your customers won’t notice a great device driver,but they’ll certainly notice if it isn’t.

  40. Related sessions • [HW-773T] Building great USB 3.0 devices • [HW-322T] Designing great devices and drivers • [HW-235T] Developing drivers in Visual Studio • [HW-907C] Inside the Windows 8 driver developer workflow • [HW-721H] Experiencing Windows Driver Kit integration with Visual Studio

  41. Further reading and documentation • Getting Started: • The WDF Book: Developing Drivers with Windows Driver Foundation by Orwick and Smith • 50% off coupon code DDWDF • Kernel-Mode Driver Framework Design Guide • User-Mode Driver Framework Design Guide • Choosing a driver model • What’s New in Windows Driver Frameworks for Windows 8 • Contact info – wdfinfo@microsoft.com • Blogs - Mine, and others about WDF

  42. thank you Feedback and questions http://forums.dev.windows.com Session feedbackhttp://bldw.in/SessionFeedback

  43. © 2011 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.

More Related