How to Develop a UMDF Driver Part 1

  • Slides: 161
Download presentation
How to Develop a UMDF Driver Part 1

How to Develop a UMDF Driver Part 1

Outline Architectural Goals Architectural Description Core components Driver Manager, Reflector, Host Process, and Drivers

Outline Architectural Goals Architectural Description Core components Driver Manager, Reflector, Host Process, and Drivers Driver startup and teardown I/O flow Layered drivers Driver Programming Model WDF object model COM-lite UMDF DDIs

Goals An understanding of UMDF infrastructure An understanding of the UMDF DDIs and how

Goals An understanding of UMDF infrastructure An understanding of the UMDF DDIs and how they are structured

Architectural Goals Stability Driver failures should NOT bring down the system Build on Windows

Architectural Goals Stability Driver failures should NOT bring down the system Build on Windows NT I/O model Applications are transparent to driver runtime environment – User or Kernel mode Asynchronous, layered drivers, and packet based Integrate into Pn. P for device installs, driver load/unload Security Driver failures should NOT compromise the system Driver runs in “Local. Service” account Shared model between KMDF and UMDF Shared model != same DDIs or data structures

Architectural Block Diagram Application(s) Driver Manager Host Process UM Driver Win. Sock User Kernel

Architectural Block Diagram Application(s) Driver Manager Host Process UM Driver Win. Sock User Kernel Reflector Windows Kernel (I/O Mgr, Pn. P) Reflector Kernel Driver (e. g. , Win. USB) Provided by: Microsoft ISV IHV Kernel Driver 2 Device Stack

UMDF Components Driver manager Global, system-wide Windows Service Responsible for host process lifetime Responds

UMDF Components Driver manager Global, system-wide Windows Service Responsible for host process lifetime Responds to messages from reflector Always running Started during installation of the first UMDF device Host Process Driver Manager UM Driver Reflector

UMDF Components Reflector Nucleus of UMDF Installed with each device stack Proxy for UM

UMDF Components Reflector Nucleus of UMDF Installed with each device stack Proxy for UM device stack in kernel Forwards I/O, Power, and Pn. P messages from kernel to host process Ties the UM device stack to KM side Ensures “good behavior” of UM drivers Proper responses to messages Timely completion of critical system messages Tracks all outstanding kernel resources Host Process Driver Manager UM Driver Reflector

UMDF Components : Host Process Child process of the UM Driver Manager Unit of

UMDF Components : Host Process Child process of the UM Driver Manager Unit of isolation for the device stack Driver crash will not affect other device stacks Container for Framework and UM driver(s) Runtime environment for framework and driver I/O dispatching, driver loading, driver layering, thread pool Handles messages from reflector and driver manager Driver Manager Runtime Reflector Framework DDI UM Driver

Host Process - Framework Implements all of the WDF model Queues, Request, I/O target,

Host Process - Framework Implements all of the WDF model Queues, Request, I/O target, etc Implements default behavior Reduces vendor written code Exposes DDI Implemented as DLL Runtime Framework DDI UM Driver

IPC : Message Passing Requirements Packet-based and asynchronous Cancelable Fail-safe Efficient data transfer Secure

IPC : Message Passing Requirements Packet-based and asynchronous Cancelable Fail-safe Efficient data transfer Secure Several potential solution Pending I/O, synchronous message passing Windows codenamed “Longhorn” solution: ALPC Standard Windows OS Component

Processing Messages KM drivers handle I/O in caller’s thread Obviously not a option for

Processing Messages KM drivers handle I/O in caller’s thread Obviously not a option for UMDF Host has a thread pool processing messages Dedicated thread for “critical” operations To ensure I/O doesn’t block them e. g. , Pn. P/PM, Cancellation, Cleanup, and Close Shared threads for non-critical operations like I/O Pool could grow or shrink as load changes Fixed at 2 threads for Beta 1 For long operations the driver should consider using work-items

Driver Loading 5 Driver Manager 3 Host Runtime 2 Windows Kernel (I/O Mgr, Pn.

Driver Loading 5 Driver Manager 3 Host Runtime 2 Windows Kernel (I/O Mgr, Pn. P) Provided by: Microsoft IHV 1 Add Device 6 Framework 4 UM Driver IPC Channel Reflector Kernel Driver

Driver Loading (Layered UM Drivers) 7 Driver Manager 3 Host Runtime 8 5 6

Driver Loading (Layered UM Drivers) 7 Driver Manager 3 Host Runtime 8 5 6 2 Windows Kernel (I/O Mgr, Pn. P) Provided by: Microsoft IHV 1 Add Device UM Filter Driver Framework 4 UM Driver IPC Channel Reflector Kernel Driver

Driver Loading (Host Process) Add Device Host Runtime Add Device Driver creates WDF Device

Driver Loading (Host Process) Add Device Host Runtime Add Device Driver creates WDF Device Framework UM Driver creates WDF Queue Add Device Provided by: Microsoft IHV

I/O Data Flow UM I/O Mgr 1 5 Host Process Application 4 Device Stack

I/O Data Flow UM I/O Mgr 1 5 Host Process Application 4 Device Stack 6 7 8 Win 32 I/O API UM Filter Driver Framework 9 10 11 3 UM Driver 12 IPC Message Windows Kernel IRP 2 “Up” Device Object “Down” Device Object Reflector Provided by: Microsoft ISV IHV Kernel driver

I/O in Host Process Invoke driver callback passing in I/O request Run-time Host File

I/O in Host Process Invoke driver callback passing in I/O request Run-time Host File Object UM IRP UM Irp Framework Device Stack IPC Message Host File Object returned as context to the reflector. Provided by: Microsoft ISV IHV Driver can return without completing i/o (asynch) Driver eventually completes i/o. UM Driver

Device Removal and Cleanup Run-time Framework UM Driver Device Remove Message path similar to

Device Removal and Cleanup Run-time Framework UM Driver Device Remove Message path similar to “add device” path Driver gets several Pn. P notifications for remove UM driver may unload when remove finishes Host process may exit when all drivers are unloaded Host lifetime controlled by the driver manager

When Driver or Application Crashes When the UM driver crashes: Reflector gets notification from

When Driver or Application Crashes When the UM driver crashes: Reflector gets notification from OS Reflector tracks outstanding I/O in the host. Completed with STATUS_DRIVER_PROCESS_TERMINATED Win 32 apps will see ERROR_DRIVER_PROCESS_TERMINATED The kernel drivers for the device stack are unloaded Device is disabled (yellow bang in device manager) When the application crashes: Reflectors gets IRP_MJ_CLEANUP Sent to host on the “cancel” IPC channel Host/UM driver complete pending I/O requests

Timeout Policy UMDF enforces timeouts on “critical” operations Operations that run under system wide

Timeout Policy UMDF enforces timeouts on “critical” operations Operations that run under system wide locks Operations that affect user experience If operations do not complete on time Host is forcibly terminated and error report is generated Critical operations include Pn. P and PM operations These run under a system-wide Pn. P lock Blocks other Pn. P operations I/O Cancellation Long term operations must be cancelable Adversely affects user experience (application hangs) In Win. HEC release, time out = 1 minute Will adjust based on feedback & failure report data for RTM

Impersonation Driver runs in Local. Service security context Drivers can impersonate the client process

Impersonation Driver runs in Local. Service security context Drivers can impersonate the client process Only for I/O requests Not for Pn. P or other system messages typedef enum _SECURITY_IMPERSONATION_LEVEL { Security. Anonymous, Security. Identification, Security. Impersonation, Security. Delegation } SECURITY_IMPERSONATION_LEVEL;

Using Impersonation Application controls the allowed level Specified in QOS settings in Create. File

Using Impersonation Application controls the allowed level Specified in QOS settings in Create. File API See dw. Flags. And. Attributes parameter in MSDN INF sets the driver’s maximum desired level Stored in registry during device installation Set this as low as possible for your driver Reduces chance of “elevation of privilege” attack Driver requests impersonation for given request Specifies desired level and a callback Isolate impersonated code Do minimal work to reduce the attack surface

UMDF Verifier Built-in verification Checks for problems in framework code Checks for problems in

UMDF Verifier Built-in verification Checks for problems in framework code Checks for problems in device driver code Always enabled & always fatal Unless you have a debugger attached DDI misusage result in verifier failure Passing incorrect parameters, including NULL, in DDI Incorrect DDI call sequence More aggressive checks planned for Beta 2 Verifier failure causes a UMDF “Bugcheck” Generates Memory Dump Generates Error Report Sends Error Report to Microsoft (opt-in)

UMDF Verifier Failures Driver failures will “Bugcheck” the host Bugcheck is NOT the “Blue

UMDF Verifier Failures Driver failures will “Bugcheck” the host Bugcheck is NOT the “Blue Screen of Death” We will pick a less scary name in Beta 2 Bugcheck will: Save memory dump to log file directory %windir%System 32Log. FilesWUDFxxx. dmp Create an error report to Microsoft (opt-in) Break into debugger if present Prints out error message Developer can continue…but that may lead to another crash Terminate the host process and disable the device

UMDF Error Reporting Current driver failure reports are hard to analyze Too much information

UMDF Error Reporting Current driver failure reports are hard to analyze Too much information in the running kernel Not enough fits into a minidump User-Mode Drivers reports can be better Compartmentalized – less information to collect Specialized – not mixed with irrelevant state Better collection – we’re not limited by crash dump UMDF reports problems through Windows Error Reporting (WER) UMDF queues reports for later approval and upload WER provides for a global “opt-in” to upload quicker No modal crash dialogs Bubble on the task bar indicating an incident has occurred Please upload error reports for Beta 1 Even if you think it’s your driver We need data to refine what we’re collecting

Types of Error Reports UMDF will report the following problems : UM Driver Verifier

Types of Error Reports UMDF will report the following problems : UM Driver Verifier failure Unhandled Exception in host process Unexpected Host Termination Failure or Timeout of “Critical” Operation Error Report may contain: Memory dump of the host process Copy of UMDF’s internal trace log Configuration information about the device Device name, manufacturer, drivers installed Driver binary versions Internal analysis of the problem Address of the last driver to framework call (or vice versa) Problem code, exception info, etc. . . Report contents depend on the problem detected

Device Driver Interfaces (DDI) and Programming Patterns

Device Driver Interfaces (DDI) and Programming Patterns

Framework Object Model Framework objects have a hierarchical relationship WDF Driver is the root

Framework Object Model Framework objects have a hierarchical relationship WDF Driver is the root object Child lifetime scoped by parent Every WDF object is defined by Methods: actions on objects Properties: are object attributes Events: notifications from Framework objects to the driver WDF Device WDF Queue

Key Framework Objects Object Driver Device I/O Request I/O Queue File I/O Target Description

Key Framework Objects Object Driver Device I/O Request I/O Queue File I/O Target Description Supports one or more devices One per driver per host process Tracks Pn. P/PM state changes and notifies driver Represents application’s I/O request Controls I/O request flow into driver Provides per-handle context for driver Represents next lower device in stack Encapsulates driver to driver communication

Parent-Child Object Hierarchy Applies to lifetime management Lifetime of child is scoped within that

Parent-Child Object Hierarchy Applies to lifetime management Lifetime of child is scoped within that of the parent Child is cleaned up when the parent goes away Driver Device I/O Queue File I/O Request I/O Target

Framework Object Model Framework Driver WDF Driver My. Device WDF Queue WDF Objects Provided

Framework Object Model Framework Driver WDF Driver My. Device WDF Queue WDF Objects Provided by: Microsoft IHV My. Read Queue My. Write Queue Driver implemented Callback Objects

Framework Object Model Framework Driver 1 My. Driver 1 WDF Driver My. Device 1

Framework Object Model Framework Driver 1 My. Driver 1 WDF Driver My. Device 1 WDF Device WDF Queue WDF Driver Device Stack WDF Device WDF Queue My. Write Queue 1 My. Device 2 My. Read Queue 1 My. Driver 2 My. Write Queue 2 Driver 2 Each driver in the stack has its own set of framework objects

DDI Design Common object model with KMDF Driver writers familiar with KMDF can quickly

DDI Design Common object model with KMDF Driver writers familiar with KMDF can quickly come up to speed with UMDF Interface based programming model UM developers are familiar with C++ and OOP Interfaces allow logical grouping of functions making it easy to navigate through the DDI Facilitates opt-in programming Built-in extensibility C++ is the supported language in the first version Uses a small subset of COM (COM-Lite) COM complexity is in COM RTL features Threading Model, Automation, etc. . . UMDF doesn’t depend on COM RTL

DDI : COM Interfaces Problems solved by Interfaces Allows us to evolve the DDI

DDI : COM Interfaces Problems solved by Interfaces Allows us to evolve the DDI without changing exported functions Older drivers do not need to be rebuilt No C++ name mangling No C++ fragile base class problem COM facilitates this Well understood Existing tools like ATL We don’t want to invent another model C++ facilitates this Interfaces are just abstract base classes With only pure virtual functions Compiler implements interface as function pointer table (V-Table)

All You Need to Know about COM … COM interfaces, by convention, start with

All You Need to Know about COM … COM interfaces, by convention, start with “I” e. g. , IUnknown All COM interfaces are derived from IUknown Query. Interface, Add. Ref, Release Lifetime management of COM objects Add. Ref: takes a reference on Framework object WDF object model simplifies ref-counting Release: drops ref-count on Framework object Driver should release interfaces retrieved from Fx when done Query Interface (QI): allows discovery of “interfaces” supported by the driver

Device Driver Interfaces (DDI) UMDF DDI is in wudfddi. idl interface IWDFObject : IUnknown

Device Driver Interfaces (DDI) UMDF DDI is in wudfddi. idl interface IWDFObject : IUnknown { HRESULT Delete. Wdf. Object(); . . . VOID Acquire. Lock(); VOID Release. Lock(); }; Simplified C++ equivalent generated by MIDL struct IWDFObject : public IUnknown { virtual HRESULT Delete. Wdf. Object() = 0; . . . virtual VOID Acquire. Lock() = 0; virtual VOID Release. Lock() = 0; }; IWDFObject is base interface for all WDF objects

Device Driver Interfaces (DDI) DDIs are grouped into 2 types of interfaces Functionality exported

Device Driver Interfaces (DDI) DDIs are grouped into 2 types of interfaces Functionality exported by Framework By convention these begin with IWDF E. g. , IWDFDriver, IWDFDevice, IWDFIo. Queue Callbacks exported by Driver These are of the form I<Wdf. Object><Function> e. g. , IQueue. Callback. Read, IRequest. Callback. Cancel Methods on callback interfaces begin with “On” interface IQueue. Callback. Read : IUnknown { void On. Read ( IWDFIo. Queue* p. Wdf. Queue, IWDFIo. Request* p. Wdf. Request, SIZE_T Num. Of. Bytes. To. Read ); };

Device Driver Interfaces (DDI) KMDF and UMDF DDI are similar Tuned to language and

Device Driver Interfaces (DDI) KMDF and UMDF DDI are similar Tuned to language and runtime environment KMDF NTSTATUS Wdf. Device. Configure. Request. Dispatching( WDFDEVICE Device, WDFQUEUE Queue, WDF_REQUEST_TYPE Request. Type, BOOLEAN Forward ); UMDF HRESULT IWDFDevice: : Configure. Request. Dispatching( IWDFIo. Queue * p. Queue, WDF_REQUEST_TYPE Request. Type, BOOL Forward ); Device parameter is implicit in C++

Driver Entry IDriver. Entry is the top driver-exported interface IDriver. Entry: : IUnknown {

Driver Entry IDriver. Entry is the top driver-exported interface IDriver. Entry: : IUnknown { HRESULT On. Initialize( IWDFDriver* p. Wdf. Driver ); HRESULT On. Device. Add( IWDFDriver* p. Wdf. Driver, IWDFDevice. Initialize* p. Wdf. Device. Init ); VOID On. Deinitialize(); }; On. Initialize and On. Deinitialize Do driver-wide initialization and cleanup On. Device. Add Invoked once for each new device detected by Windows

Callback Objects Callback objects = Callbacks + Context Example: Creating Device Object HRESULT CMy.

Callback Objects Callback objects = Callbacks + Context Example: Creating Device Object HRESULT CMy. Driver: : On. Device. Add( IWDFDriver* p. Driver, IWDFDevice. Initialize* p. Device. Init ) { IUnknown *p. Device. Callback = NULL; . . . // Create callback object hr = CMy. Device: : Create. Instance( &p. Device. Callback, 1 p. Device. Init, completion. Port ); . . . // Create WDF Device hr = p. Driver->Create. Device( p. Device. Init, p. Device. Callback, 2 &p. IWDFDevice ); . . . }

Callback Objects (con’t) class CMy. Device : public IDevice. Pnp. Hardware { private: HANDLE

Callback Objects (con’t) class CMy. Device : public IDevice. Pnp. Hardware { private: HANDLE WINUSB_INTERFACE HANDLE UCHAR ULONG. . . public: virtual HRESULT stdcall // Callback interface exposed to // framework. m_Completion. Port; m_Usb. Handle; m_Bulk. Out. Pipe; m_Bulk. Out. Max. Packet; On. Prepare. Hardware( IWDFDevice* p. Device ); STDMETHOD( On. Release. Hardware )( IWDFDevice *p. Device ); // Factory method static HRESULT Create. Instance( IUnknown *p. Unknown, IWDFDevice. Initialize *p. Device. Init, HANDLE Completion. Port ); . . . }; Context Callback

Callback Objects (con’t) static HRESULT Create. Instance( IUnknown **pp. Unknown, IWDFDevice. Initialize *p. Device.

Callback Objects (con’t) static HRESULT Create. Instance( IUnknown **pp. Unknown, IWDFDevice. Initialize *p. Device. Init, HANDLE Completion. Port ) {. . . // Allocate our callback context 1 CMy. Device *p. My. Device = new CMy. Device(); . . . // Get our callback interface 2 hr = p. My. Device->Query. Interface( __uuidof(IUnknown), (void **) pp. Unknown ); . . . return hr; }

Callback Objects (con’t) 1 On. Device. Add IDriver. Entry Callback Object WDF Driver 2

Callback Objects (con’t) 1 On. Device. Add IDriver. Entry Callback Object WDF Driver 2 IWDFDriver: : Create. Device( … ) 3 WDF Device 5 Framework Provided by: Microsoft IHV 4 Query. Interface for • IDevice. Pn. PHardware ---- IUnknown My. Device IDevice. Pnp. Hardware Driver

Summary Discussed driver loading/unloading, I/O data flow Driver installation and setup are same as

Summary Discussed driver loading/unloading, I/O data flow Driver installation and setup are same as WDM drivers Keep in the mind the “timeout” polices in reflector Built-in verifier checks Error reporting via WER Discussed driver programming model KMDF and UMDF share same model UMDF DDI is based on C++ and COM-lite Callback objects = Context + Callbacks

How to Develop a UMDF Driver Part 2

How to Develop a UMDF Driver Part 2

Outline Goals Getting Started Writing your Driver Installing your Driver Debugging the Driver Plug

Outline Goals Getting Started Writing your Driver Installing your Driver Debugging the Driver Plug and Play / Power Management Design goals Design overview Device Driver Interface (DDI) Pn. P/PM driver callback example

Goals How to start writing and debugging a UMDF driver How to interact with

Goals How to start writing and debugging a UMDF driver How to interact with UMDF’s Plug And Play and Power Management support The basics of creating and configuring a device driver

Writing Your Driver

Writing Your Driver

What is a User-Mode Driver? User-Mode (UM) Drivers are DLLs Provide driver’s “callback object”

What is a User-Mode Driver? User-Mode (UM) Drivers are DLLs Provide driver’s “callback object” classes Use COM programming pattern, not runtime At least, not very much of the runtime Expose standard COM entry points Dll. Get. Class. Object, Dll. Register. Server, Dll. Unregister. Server Can write UM Drivers in C or C++ Implementing COM objects is easier in C++ Can use ATL with C++ for additional COM support WDF Supplement CD contains several examples This talk references the “Skeleton” driver

UMDF Driver DLL Exports Dll. Main Called when DLL loads (and unloads) Construct global

UMDF Driver DLL Exports Dll. Main Called when DLL loads (and unloads) Construct global objects, initialize tracing Dll[Un]Register. Server Called by Co. Installer during device installation Skeleton sample uses ATL Rather than write another implementation Dll. Get. Class. Object Called on device arrival by COM to get “class factory” Dll. Can. Unload. Now Just return S_FALSE

Common Driver Classes COM objects must implement IUnknown Independently, or with help from CUnknown

Common Driver Classes COM objects must implement IUnknown Independently, or with help from CUnknown base class UMDF driver implements these classes CClass. Factory Instantiates your driver event handler CMy. Driver Your Driver-Callback Class Must implement IDriver. Entry Paired with an IWDFDriver object CMy. Device Your Device-Callback Class May implement IDevice. Pnp. Hardware and/or IDevice. Pnp Paired with an IWDFDevice object

UMDF Skeleton Driver Example code based on UMDF Skeleton sample Code in slides should

UMDF Skeleton Driver Example code based on UMDF Skeleton sample Code in slides should not be used as-is UMDF Skeleton does just enough to get loaded Boilerplate code found in all UM Drivers Minimal callback objects for driver and device Description of files Com. Sup. h & Com. Sup. cpp COM Support code – provides classes for IUnknown & IClass. Factory Dll. Sup. h & Dll. Sup. cpp DLL Support code – provides implementation of required exports Depends on COM support code Driver. h & Driver. cpp Driver-Callback Class Device. h & Device. cpp Device-Callback Class “TODO” comments mark where to add your driver code COM and DLL support files require no changes The driver and device files you’ll need to modify for your driver

Example: CMy. Driver Definition (Driver. h) class CMy. Driver: public CUnknown, public IDriver. Entry

Example: CMy. Driver Definition (Driver. h) class CMy. Driver: public CUnknown, public IDriver. Entry { IDriver. Entry *Query. IDriver. Entry(); HRESULT Initialize(); public: static HRESULT Create. Instance( PCMy. Driver *Driver ); HRESULT On. Initialize( IWDFDriver *Fx. Driver ){ return S_OK; } HRESULT On. Device. Add(IWDFDriver *Fx. Driver, IWDFDevice. Initialize *Fx. Device. Init); HRESULT On. Deinitialize( IWDFDriver *Fx. Driver ) { return S_OK; }. . . // IUnknown methods, etc. . . };

Example: CMy. Driver Implementation (Driver. cpp) HRESULT CMy. Driver: : Create. Instance( CMy. Driver

Example: CMy. Driver Implementation (Driver. cpp) HRESULT CMy. Driver: : Create. Instance( CMy. Driver **Driver ) { CMy. Driver *driver = new CMy. Driver(); if (driver == NULL) { return E_OUTOFMEMORY; } HRESULT hr = driver->Initialize(); if (S_OK == hr) { *Driver = driver; } else { driver->Release(); } return hr; } HRESULT CMy. Driver: : Initialize() { HRESULT hr = S_OK; . . . // Do any initialization that could fail here return hr; }

Example: CMy. Driver Implementation (con’t) HRESULT CMy. Driver: : On. Device. Add(. . .

Example: CMy. Driver Implementation (con’t) HRESULT CMy. Driver: : On. Device. Add(. . . ) { CMy. Device *device. Callback; IWDFDevice *fx. Device; HRESULT hr = CMy. Device: : Create. Instance( Fx. Device. Init, &device ); if (S_OK == hr) {. . . // Call Set. Locking. Model(), Set. Filter(), etc. . . hr = Fx. Wdf. Device->Create. Device( Fx. Device. Init, device. Callback->Query. IUnknown(), &fx. Device ); // Release Reference from Query. IUnknown() device. Callback->Release(); } if (S_OK == hr) {fx. Device->Release(); } if (NULL != device. Callback) {device. Callback->Release(); } return hr; }

Example: CMy. Device Definition (Device. h) class CMy. Device : public CUnknown { HRESULT

Example: CMy. Device Definition (Device. h) class CMy. Device : public CUnknown { HRESULT Initialize( IWDFDevice. Initialize *Device. Init ) { return S_OK; } static HRESULT Create. Instance( IWdf. Device. Initialize *Fx. Device. Init, CMy. Device **Device ); // Add IUnknown methods here }

Writing Your Driver (Summary) Create the common code Required DLL Exports COM support classes

Writing Your Driver (Summary) Create the common code Required DLL Exports COM support classes Copy from skeleton, use existing ones (ATL), or write your own Implement CMy. Driver class Including the On. Device. Add() method Allocate and initialize a CMy. Device object Create IWDFDevice object & connect to CMy. Device callbacks Implement CMy. Device class Add Device-Callback interfaces later Your driver should now load But can’t talk to your device or do I/O Next two talks will address that

Installing Your Driver INF Based Installation Just like WDM and kernel-mode WDF drivers Device

Installing Your Driver INF Based Installation Just like WDM and kernel-mode WDF drivers Device Matching, Driver Signing, etc. . . work normally User-Mode Driver’s INF does extra work Use UMDF Co. Installer Register Driver DLLs Configure the Driver List Setup UM Driver Key Add the Reflector driver We plan to simplify the installation for Beta 2 Still INF based, but more support from Co. Installer

Registry Locations UMDF keeps information in several registry keys We’ll refer to them using

Registry Locations UMDF keeps information in several registry keys We’ll refer to them using these names as we go Defined in the [Strings] section of the Skeleton INF Key Name Location %UMDF_Software% HKLM Software Microsoft Windows NT Current. Version WUDF %UMDF_Services% %UMDF_Software% Services %UMDF_Host% %UMDF_Services% {193 a 1820 -d 9 ac-4997 -8 c 55 -be 817523 f 6 aa}

Use UMDF Co. Installer System provided Co. Installer Sets Driver Manager to start automatically

Use UMDF Co. Installer System provided Co. Installer Sets Driver Manager to start automatically WUDFCo. Installer. dll is already installed No need to copy the file Driver’s INF must reference this Co. Installer [Skeleton. Co. Installers] Add. Reg = Skeleton. Co. Installers_Add. Reg [Skeleton. Co. Installers_Add. Reg] HKR, , Co. Installers 32, 0 x 00010000, “WUDFCo. Installer. dll” Without the Co. Installer your driver may not start Driver can’t start if the Driver Manager isn’t running Problem code 37 in device manager

Register Driver DLLs UMDF uses Co. Create. Instance to load drivers This requires the

Register Driver DLLs UMDF uses Co. Create. Instance to load drivers This requires the driver to be “registered” INF must register any user-mode drivers it copies Do this in the [DDInstall] section [Skeleton] Copy. Files=Driver. Copy Register. Dlls=Skeleton. Register. Dlls [Skeleton. Register. Dlls] 11, , WUDFSkeleton. dll, 1 Unregistered drivers will not load Problem code 43 in the device manager

Configure the Driver List UMDF loads drivers by “Driver Name” We recommend the binary

Configure the Driver List UMDF loads drivers by “Driver Name” We recommend the binary name (without extension) UMDF Maintains its own driver list Lists drivers in order of attachment to the stack Drivers are listed by “Driver Name” User-Mode drivers load above kernel-mode drivers Multi. String stored under the device node’s key [Skeleton_Add. Reg] HKR, “WUDF”, “Driver. List”, 0 x 00010000, “WUDFSkeleton” If this is missing Problem 43 in device manager

Setup UM Driver Key Create an entry under UMDF Services Key One for each

Setup UM Driver Key Create an entry under UMDF Services Key One for each driver installed Key name is the Device Name Contains UMDF-Specific Driver Information: The Driver’s CLSID Configure this in the INF Replace CLSID with your driver’s class ID. [Skeleton_Add. Reg] HKLM, %WUDF_Services%WUDFSkeleton, “Com. CLSID”, 0, “{CLSID}” Without this: Problem 43 in device manager

Adding the Reflector Driver Reflector driver is WUDFRd. sys Already installed on the system

Adding the Reflector Driver Reflector driver is WUDFRd. sys Already installed on the system Your INF must make this the top-most kernel driver If you’re writing a UM function driver Assign reflector as service with Add. Service directive You’ll need a service install section too If you’re writing a UM Upper-Level filter driver Assign reflector as top-most Upper Device Filter Without this UMDF is never loaded Device may start, but no host process

Installing Your Driver (Summary) Use the UMDF Co. Installer Register your Driver DLLs with

Installing Your Driver (Summary) Use the UMDF Co. Installer Register your Driver DLLs with COM Configure the Driver List Setup UM Driver Key Record your driver’s CLSID Add Reflector driver to the kernel drivers If it doesn’t work: Is Driver Manager started? Does device manager show a problem code? Is WUDFHost. exe (host process) running ?

Debugging Your Driver

Debugging Your Driver

Debugging Overview Similar to service debugging UM Drivers cannot be started by the debugger

Debugging Overview Similar to service debugging UM Drivers cannot be started by the debugger No Just-In-Time debugging Host process starts when device is installed Plug & Replug the device to restart Or disable & re-enable in device manager Each device stack runs in host process WUDFHost. exe Child of Driver Manager service One stack per host-process for now

Debugger Options Win. Dbg GUI Debugger Source and/or Assembly level debugging UMDF debugger extension

Debugger Options Win. Dbg GUI Debugger Source and/or Assembly level debugging UMDF debugger extension available Can work as user-mode or kernel-mode debugger See resources slide to find download location Visual Studio Debugger WDK and Visual Studio aren’t currently integrated UMDF Debugger extension not available Must copy mspdb 71. dll from WDK to use it We’re concentrating support on Win. Dbg CDB & KD If you prefer command line debugging, these work

User-Mode or Kernel-Mode Debugging Can debug UMDF with UM or KM debugger You can

User-Mode or Kernel-Mode Debugging Can debug UMDF with UM or KM debugger You can use Win. Dbg to debug either way UM Debugger Simpler and more familiar Have to attach to each host process when it starts KM Debugging Requires a second computer to run debugger More complex, but quite powerful Stops entire computer – no UMDF timeouts Can be always running Catch UMDF Verifier problems like JIT debugger Can debug and set breakpoints in host process Use “. process /i <process object address>” to break into running host See additional slides for KM Debugging tips

Enabling the Debugger Host process started by Driver Manager service You can’t attach debugger

Enabling the Debugger Host process started by Driver Manager service You can’t attach debugger until after initialization Host Process supports an “initial breakpoint” (IB) Host waits N seconds for debugger to attach Breaks into debugger once detected Continues running once N seconds elapse Timeout (in seconds) configured under UMDF_Host key Host. Process. Dbg. Break. On. Start = N Enabling IB disables other UMDF timeouts Like those on Pn. P operations Initial Breakpoint is for UM Debugger (by default) Can be configured to watch for both UM & KM debugger Set high-bit in the timeout value 0 x 8000000 attempts once to break into either debugger

Attaching the UM Debugger Cannot connect UM Debugger until host starts Enable the Initial

Attaching the UM Debugger Cannot connect UM Debugger until host starts Enable the Initial Breakpoint Attach the device to the system Or enable it in the device manager If you have a single device attached Run “windbg –pn WUDFHost. exe” Repeat until it finds a host process to debug If you have multiple devices attached Find out process ID (PID) of the new host Use tasklist. exe before & after to find new host process Run “windbg –p PID”

UMDF Debugger Extension Wudf. Ext. dll Copy into your path “!load Wudf. Ext. dll”

UMDF Debugger Extension Wudf. Ext. dll Copy into your path “!load Wudf. Ext. dll” debugger command loads the extension Names are case sensitive Command !devstack !dumpirps !umirp !wdfdriverinfo !wdfdevicequeue !wdfrequest !wdfitf 2 obj Description Shows device stacks in the host process Shows UM IRPs in the host process Shows a host IRP Shows info about a UM driver Shows the I/O queues for a device Shows an Io. Queue Shows an Io. Request Converts an interface pointer to an object address for above extensions.

Interesting UMDF Breakpoints (BP) Hopefully, this will get you started Event to debug Host

Interesting UMDF Breakpoints (BP) Hopefully, this will get you started Event to debug Host attempts to load driver Driver Load Breakpoint (BP) OLE 32!Co. Create. Instance Watch for your CLSID My. Driver!Dll. Main Invoked first time when your DLL is loaded Called after that too, so clear the BP once it hits Creation of CMy. Driver attaches device to stack My. Driver!Dll. Get. Class. Object Invoked to get your class factory My. Driver!CMy. Driver: : CMy. Driver Invoked when the factory calls new My. Driver!CMy. Driver: : On. Device. Add Driver creates a device to attach to the stack

Tracing in Your UM Driver Recommend using WPP tracing for debug output Lightweight &

Tracing in Your UM Driver Recommend using WPP tracing for debug output Lightweight & always available, printf-style tracing Easily captured to disk, screen or (kernel) debugger Skeleton contains some basic tracing code See MSDN documentation on Event Tracing Collect output with tracelog. exe or traceview. exe Tracelog comes with Windows Traceview comes with WDK For more information see: “Collecting & Viewing Traces” in additional slides MSDN & DDK documentation

What Do I Do When It Crashes? (Summary) Check for configuration problems Is there

What Do I Do When It Crashes? (Summary) Check for configuration problems Is there a PNP problem code? Is there a host process running? Is there a. dmp file WUDF log file directory? %System. Root%Log. FilesWUDF*. dmp Attach a debugger to the host as it starts Or always enable the kernel debugger Watch for UMDF Verifier failures Walk through initialization Use list of interesting breakpoints Get debug output with WPP tracing

Plug and Play / Power Management

Plug and Play / Power Management

UMDF Design Goals for Pn. P/PM Coordinate I/O delivery to driver with Pn. P/PM

UMDF Design Goals for Pn. P/PM Coordinate I/O delivery to driver with Pn. P/PM events The framework handles complexities of Pn. P/PM Allow drivers to participate with optional callbacks Support FDO and filter driver scenarios No bus driver support for version 1 Same design as kernel mode WDF Pn. P/PM

UMDF Pn. P/PM Design Implemented with a state machine Consumes Pn. P/Power messages from

UMDF Pn. P/PM Design Implemented with a state machine Consumes Pn. P/Power messages from the reflector Suspends and resumes I/O queues as needed Calls the driver if desired through a set of driver provided callback functions Driver callbacks are logically grouped into interfaces IDevice. Pnp. Hardware IDevice. Pnp. Self. Managed. Io Driver “opts-in” by implementing one or more callback interfaces Software-only drivers generally don’t need any of these interfaces Most drivers will only need IDevice. Pnp. Hardware

UMDF Pn. P/PM Interfaces IDevice. Pnp. Hardware First time hardware initialization / de-initialization On.

UMDF Pn. P/PM Interfaces IDevice. Pnp. Hardware First time hardware initialization / de-initialization On. Prepare. Hardware() On. Release. Hardware() IDevice. Pnp Device state change notifications On. D 0 Entry() On. D 0 Exit() On. Surprise. Removal() On. Query. Remove() On. Query. Stop() IDevice. Pnp. Self. Managed. Io Custom I/O processing notifications On. Self. Managed. Io. Cleanup() On. Self. Managed. Io. Flush() On. Self. Managed. Io. Init() On. Self. Managed. Io. Suspend() On. Self. Managed. Io. Restart()

Device Driver Interface (DDI) IDriver. Entry: : On. Device. Add Driver must implement this

Device Driver Interface (DDI) IDriver. Entry: : On. Device. Add Driver must implement this interface Called when framework receives “Add Device” message Driver should perform initialization that does not require access to hardware or lower level drivers Driver also creates a device object and device callback object (beyond the scope of this talk) HRESULT CMy. Driver: : On. Device. Add( IWDFDriver* p. Driver, IWDFDevice. Initialize* p. Device. Init ) { // Read in driver properties INamed. Property. Store * p. Prop. Store = NULL; hr = p. Device. Init->Get. Device. Property. Store( &p. Prop. Store ); . . . }

IDevice. Pnp. Hardware On. Prepare. Hardware Called when device is first started Driver establishes

IDevice. Pnp. Hardware On. Prepare. Hardware Called when device is first started Driver establishes connection to the device and performs one-time initialization HRESULT CMy. Device: : On. Prepare. Hardware( IWDFDevice* p. Device ) {. . . // Open the device hr = p. Device->Get. Device. Name( p. Device. Name, … ) m_Handle = Create. File( p. Device. Name, … ). . . // Initialize the device and look for endpoints if (Win. Usb_Initialize( m_Handle, &m_Usb. Handle )) { return Discover. Bulk. Endpoints(); }

IDevice. Pnp. Hardware On. Release. Hardware Called when device is removed or stopped Driver

IDevice. Pnp. Hardware On. Release. Hardware Called when device is removed or stopped Driver should essentially undo anything it did in On. Prepare. Hardware HRESULT CDevice: : On. Release. Hardware( IWDFDevice* p. Device ) { // Close the USB handle and the device’s file // handle if ( m_Usb. Handle ) { Win. Usb_Free( m_Usb. Handle ); } if ( m_Handle ) { Close. Handle( m_Handle ); } return S_OK; }

IDevice. Pnp On. D 0 Exit Called each time device should power down Also

IDevice. Pnp On. D 0 Exit Called each time device should power down Also called before the device is removed Stop device’s I/O target with “leave pending I/O” flag hr = m_p. Io. Target-> Stop( Wdf. Io. Target. Leave. Sent. Io. Pending ); Save device state Set the device into low power state On. D 0 Entry Called each time device should power up Also called when the device starts up Set the device into working power state Restore any previously saved state Restart device’s I/O target hr = m_p. Io. Target->Start();

IDevice. Pnp On. Surprise. Removal Called when the device has unexpectedly detached from the

IDevice. Pnp On. Surprise. Removal Called when the device has unexpectedly detached from the PC Stop device’s I/O target with cancel flag hr = m_p. Io. Target->Stop( Wdf. Io. Target. Cancel. Sent. Io ) On. Query. Remove Allows driver to veto a device removal request HRESULT CDevice: : On. Query. Remove( IWDFDevice* p. Device ) { return S_OK; // Allow device removal } On. Query. Stop Allows driver to veto a device stop request HRESULT CDevice: : On. Query. Stop( IWDFDevice* p. Device ) { return E_FAIL; // Disallow device stop }

IDevice. Pnp. Self. Managed. Io Notifications to drivers that perform I/O dispatching unmanaged by

IDevice. Pnp. Self. Managed. Io Notifications to drivers that perform I/O dispatching unmanaged by the framework On. Self. Managed. Io. Init() Start I/O dispatching On. Self. Managed. Io. Suspend() Pause I/O dispatching On. Self. Managed. Io. Restart() Resume I/O dispatching On. Self. Managed. Io. Flush() Cancel or complete all pending I/O On. Self. Managed. Io. Cleanup() Free I/O dispatching mechanisms

Pn. P/PM Driver Callback Example

Pn. P/PM Driver Callback Example

Start Device On. Prepare. Hardware() Device Driver Framework Start Device Off On Off

Start Device On. Prepare. Hardware() Device Driver Framework Start Device Off On Off

Start Device On. D 0 Entry() Device Driver Framework Start Device Off On Off

Start Device On. D 0 Entry() Device Driver Framework Start Device Off On Off

Device Operational Device Driver Framework On On Off

Device Operational Device Driver Framework On On Off

Suspend Device On. D 0 Exit() Device Driver Framework Power Down On On Off

Suspend Device On. D 0 Exit() Device Driver Framework Power Down On On Off

Resume Device On. D 0 Entry() Device Driver Framework Power Up On On Off

Resume Device On. D 0 Entry() Device Driver Framework Power Up On On Off

Remove Device On. D 0 Exit() Device Driver Framework Remove Device On On Off

Remove Device On. D 0 Exit() Device Driver Framework Remove Device On On Off

Remove Device On. Release. Hardware() Device Driver Framework Remove Device On On Off

Remove Device On. Release. Hardware() Device Driver Framework Remove Device On On Off

WDM Message to UMDF Callback Mapping Start -> Query Remove -> Remove IRP_MN_START_DEVICE: On.

WDM Message to UMDF Callback Mapping Start -> Query Remove -> Remove IRP_MN_START_DEVICE: On. Prepare. Hardware() On. D 0 Entry() On. Self. Managed. Io. Init() IRP_MN_QUERY_REMOVE_DEVICE: On. Query. Remove() IRP_MN_REMOVE_DEVICE: On. Self. Managed. Io. Suspend() On. D 0 Exit() On. Self. Managed. Io. Flush() On. Release. Hardware() On. Self. Managed. Io. Cleanup()

WDM Message to UMDF Callback Mapping Start -> Surprise Removal -> Remove IRP_MN_START_DEVICE: On.

WDM Message to UMDF Callback Mapping Start -> Surprise Removal -> Remove IRP_MN_START_DEVICE: On. Prepare. Hardware() On. D 0 Entry() On. Self. Managed. Io. Init() IRP_MN_SURPRISE_REMOVAL: On. Surprise. Removal() On. Self. Managed. Io. Suspend() On. Release. Hardware() On. Self. Managed. Io. Flush() IRP_MN_REMOVE_DEVICE: On. Self. Managed. Io. Cleanup()

Pn. P/PM Timeouts Each WDM Pn. P/PM message has a timeout Currently, this timeout

Pn. P/PM Timeouts Each WDM Pn. P/PM message has a timeout Currently, this timeout is set to 1 minute The reflector will abort the host process if this timeout is exceeded Each WDM Pnp/PM message can produce multiple driver callbacks, for example: “Add. Device” results in: On. Initialize On. Device. Add 1 minute IRP_MN_START results in: On. Prepare. Hardware On. D 0 Entry On. Self. Managed. Io. Init 1 minute

Supplemental Slides

Supplemental Slides

Example: Dll. Main BOOL Dll. Main( HINSTANCE Module. Handle, DWORD Reason, PVOID Reserved )

Example: Dll. Main BOOL Dll. Main( HINSTANCE Module. Handle, DWORD Reason, PVOID Reserved ) { if (DLL_PROCESS_ATTACH == Reason) { WPP_INIT_TRACING(“Microsoft\UMDFSkeleton”); g_Module. Handle = Module. Handle; } else if (DLL_PROCESS_DETACH) == Reason) { WPP_CLEANUP(); } return TRUE; } See SkeletonHost. cpp

Example: Dll. Get. Class. Object HRESULT Dll. Get. Class. Object( REFCLSID Class. Id, REFIID

Example: Dll. Get. Class. Object HRESULT Dll. Get. Class. Object( REFCLSID Class. Id, REFIID Interface. Id, PVOID *Interface ) { PCClass. Factory factory; HRESULT hr; *Interface = NULL; if (!Is. Equal. CLSID( Class. Id, __uuidof(My. Driver. Co. Class) )) { return CLASS_E_NOTAVAILABLE; } hr = CClass. Factory: : Create. Instance(&factory); if (S_OK == hr) { hr = factory->Query. Interface(Interface. Id, Interface); factory->Release(); } return hr; }

Example: Dll. Register. Server & Dll. Can. Unload. Now HRESULT Dll. Register. Server() {

Example: Dll. Register. Server & Dll. Can. Unload. Now HRESULT Dll. Register. Server() { return Update. COMRegistration( g_Module. Handle, IDR_MYDRIVER_CLASSINFO, true, __uuidof( My. Driver. Co. Class ), L“UMDF Skeleton Sample Driver” ); } HRESULT Dll. Unregister. Server() { return Update. COMRegistration(. . . , false, . . . ) } HRESULT Dll. Can. Unload. Now() { return S_FALSE; }

Example: CUnknown Definition class CUnknown : public IUnknown { LONG m_Ref. Count; public: CUnknown()

Example: CUnknown Definition class CUnknown : public IUnknown { LONG m_Ref. Count; public: CUnknown() { m_Ref. Count = 1; } virtual ~CUnknown() { return; } IUnknown *Query. IUnknown(){ Add. Ref(); return (IUnknown *)this; } ULONG Add. Ref(); ULONG Release(); HRESULT Query. Interface( REFIID Interface. Id, PVOID *Interface ); };

Example: CUnknown Implementation ULONG CUnknown: : Add. Ref(){ return Interlocked. Increment(&m_Ref. Count); } ULONG

Example: CUnknown Implementation ULONG CUnknown: : Add. Ref(){ return Interlocked. Increment(&m_Ref. Count); } ULONG CUnknown: : Release() { ULONG count = Interlocked. Increment(&m_Ref. Count); if (count == 0) { delete this; } return count; } HRESULT CUnknown: Query. Interface(. . . ) { if (Is. Equal. IID(Interface. Id, __uuidof(IUnknown)) { *Interface = Query. IUnknown(); return S_OK; } *Interface = NULL; return E_NOINTERFACE; }

Example: CClass. Factory Definition class CClass. Factory : public CUnknown, public IClass. Factory {

Example: CClass. Factory Definition class CClass. Factory : public CUnknown, public IClass. Factory { public: IClass. Factory *Query. IClass. Factory() {. . . } // IUnknown Add. Ref() {return __super: : Add. Ref()} Release() {return __super: : Release()} Query. Interface(. . . ); // IClass. Factory HRESULT Create. Instance( IUnknown *Outer, REFIID Interface. Id, PVOID *Object ); HRESULT Lock. Server(BOOL Lock) { return S_OK; } };

Example: CClass. Factory Implementation HRESULT CClass. Factory: : Query. Interface(. . . ) {

Example: CClass. Factory Implementation HRESULT CClass. Factory: : Query. Interface(. . . ) { if(Is. Equal. IID(Interface, __uuidof(IClass. Factory)) { *Object = Query. IClass. Factory(); return S_OK; } else { return CUnknown: : Query. Interface(. . . ); } } HRESULT CClass. Factory: : Create. Instance(. . . ) { PCMy. Driver driver; HRESULT hr = CMy. Driver: : Create. Instance(&driver); if (S_OK == hr) { hr = driver->Query. Interface(Interface. Id, Object); driver->Release(); } return hr; }

Debugging with Win. Dbg Source Level GUI debugger (Most) commands work on addresses or

Debugging with Win. Dbg Source Level GUI debugger (Most) commands work on addresses or symbols Module. Name!Function. Name Module. Name!Class. Name: : Method. Name Best to always use fully resolved names Setting Breakpoints “bp <addr>” sets an excution breakpoint Use bu if the function’s module isn’t loaded yet ‘ba [w|r] [1|2|4|8] <addr>’ sets a watchpoint ba r 4 My. Driver!g_My. Array. Length Dumping Memory d<type> [address] [L<length>] type = byte, word, char, unicode, dword, quadword, string dd My. Driver!g_My. Array. Length L 1 dv dumps local variable names Dumping Types dt <variable name> dumps a specific local dt <addr> <typename> dumps an address or symbol as a type dt ? ? ? My. Driver!CMy. Device See the Win. Dbg help for more details

Debugging with a Kernel Debugger Win. Dbg can be used as a kernel debugger

Debugging with a Kernel Debugger Win. Dbg can be used as a kernel debugger Must point Kernel debugger to host process Automatic if the process requests a kernel break-in Manually through the. process command “!process 0 0” will list all process object addresses Must reload user-mode symbols after attaching “. reload /user” Or the stack trace won’t have any symbols Can set breakpoints on user-mode addresses Must load user symbols first Cannot break into a running host process Must wait for a breakpoint UMDF “Verifier” will break into KD if attached Last chance to debug before process termination

Collecting & Viewing Traces Trace. Log. exe lets you control trace sessions To start

Collecting & Viewing Traces Trace. Log. exe lets you control trace sessions To start a session Tracelog. exe -start My. Logger -guid My. Driver. ctl -level 255 -flag 65535 -f My. Log. File. etl To end a session Tracelog. exe -stop My. Logger To print a session Trace. Fmt –o My. Log. File. txt -p symbols. pri/Trace. Format My. Log. File. etl Or use the GUI “Trace. View” tool Use in place of Trace. Log or Trace. Fmt Resources: “WPP Software Tracing” page in DDK documentation MSDN online page for these tools: http: //msdn. microsoft. com/library/default. asp? url=/library/enus/ddtools/hh/ddtools/tracetools_8 eccb 8 f 7 -6 f 29 -4683 -87 bdfa 83618 c 32 eb. xml. asp

How to Develop a UMDF Driver: Part 3

How to Develop a UMDF Driver: Part 3

Outline I/O Processing Overview I/O Queues File Objects Driver Layering I/O Targets Cancellation

Outline I/O Processing Overview I/O Queues File Objects Driver Layering I/O Targets Cancellation

Goals A better understanding of: How to incorporate I/O processing in a UMDF driver

Goals A better understanding of: How to incorporate I/O processing in a UMDF driver Framework objects involved with I/O Request processing Knowledge of where to find resources for UMDF

I/O Request Processing Overview

I/O Request Processing Overview

I/O Request Processing in UMDF You’ve seen WDF Driver and Device objects These are

I/O Request Processing in UMDF You’ve seen WDF Driver and Device objects These are used to configure a device stack I/O processing involves many more objects for: Flow control and internal request routing Per request context and callbacks Connections to other drivers in the stack and/or system And some concepts that span across objects: Driver Layering Cancellation

Framework Objects Driver Device Request Memory (Input) Memory (Output) Queue File I/O Target

Framework Objects Driver Device Request Memory (Input) Memory (Output) Queue File I/O Target

Framework Objects These objects are associated with request processing All derive from IWDFObject Description

Framework Objects These objects are associated with request processing All derive from IWDFObject Description Device The information associated with a single layer in a device stack Request An I/O operation Either sent to the driver or initiated by the driver to a lower device A flow control mechanism for Requests An open handle to the device and any context the driver needs to store with it Another driver to which the Driver can send Requests Either another user-mode layer in the device stack, the kernel-mode portion of the device stack, or the top of another device stack entirely. Queue File I/O Target Memory A buffer associated with a request

I/O Request Processing – A Bird’s Eye view Request I/O Queue Driver I/O Target

I/O Request Processing – A Bird’s Eye view Request I/O Queue Driver I/O Target Complete

I/O Request Object Request I/O Queue Driver I/O Target Complete

I/O Request Object Request I/O Queue Driver I/O Target Complete

I/O Request Object Represents a request Sent to the driver by a client An

I/O Request Object Represents a request Sent to the driver by a client An application or another UM driver Generated by a driver Types of Requests presented to driver Create Read / Write / Device. Io. Control Cleanup Close Request Parameters can be obtained from IWDFIo. Request interface

I/O Queues

I/O Queues

I/O Queues Request I/O Queue Driver I/O Target Complete

I/O Queues Request I/O Queue Driver I/O Target Complete

I/O Queues provide flow control for I/O Requests All requests dispatched to driver through

I/O Queues provide flow control for I/O Requests All requests dispatched to driver through I/O Queues Driver can configure I/O routing for a device Create one or more queues for a device Configure routing for a type of I/O to a particular queue “Default queue” handles any remaining I/O types

I/O Queue Dispatch Types Dispatch Type controls how requests are presented to driver Queues

I/O Queue Dispatch Types Dispatch Type controls how requests are presented to driver Queues allow following modes of dispatching: Automatic: Queue presents requests via callbacks (Push Model) Manual: Requests are retrieved by driver (Pull Model) Dispatch type is set at Queue creation time It is a per-Queue property

Automatic Dispatch Queue presents request through driver implemented callback interfaces IQueue. Callback. Create. Close

Automatic Dispatch Queue presents request through driver implemented callback interfaces IQueue. Callback. Create. Close IQueue. Callback[Read | Write | Device. Io. Control] Automatic Dispatch Types Sequential: allows at most one outstanding request at a time New Request not presented until current request is completed Parallel: allows multiple outstanding requests New Request can be presented even when previously presented requests are not completed The number of parallel requests presented is bounded Driver should minimize blocking in presentation callbacks

Manual Dispatch Driver pulls requests from the queue Typically starts in response to Queue

Manual Dispatch Driver pulls requests from the queue Typically starts in response to Queue callback IQueue. Callback. State. Change Empty to non-empty transition Continues to pump I/O until “done” No more I/O, bookmark request retrieved, error, etc. . . Starts again on next Queue state change HRESULT Retrieve. Next. Request( OUT IWDFIo. Request** pp. Request ); It is possible for driver to pull requests from an Automatic Queue

Callback Constraints Callback constraints specify locking model for Queue callbacks Callback constraints options Device

Callback Constraints Callback constraints specify locking model for Queue callbacks Callback constraints options Device Level: Callbacks invoked with device level lock held None: Callbacks invoked with no lock held Specified at device creation time via IWDFDevice. Initialize: : Set. Locking. Constraint Set before creating the WDF Device object Per device property – applies to all queues

Callback Constraints (con’t) Constraints apply only to Queue Callbacks Queue callbacks include Automatic Dispatch

Callback Constraints (con’t) Constraints apply only to Queue Callbacks Queue callbacks include Automatic Dispatch Callbacks Queue state change callback Request cancellation callback If Device Level locking is used: The above callbacks are synchronized Request Completion is a not a Queue Callback – not synchronized Unsynchronized code can call IWDFObject: : Acquire. Lock Call on object that matches your synchronization scope

Dispatch Type vs. Locking Model Combining Dispatch Type and Locking Model provides several modes

Dispatch Type vs. Locking Model Combining Dispatch Type and Locking Model provides several modes of operation For example: Sequential Queue Device Level Locking Parallel Queue Device Level Locking Request 1 Req 1 Complete Request 2 Req 1 Complete Req 2 Complete Parallel Queue No Locking Request 1 Request 2 Req 1 Complete Req 2 Complete

UMDF OSR USB Sample Walk-through Requests and Queue Usage in the sample driver (srcumdfusbdriver)

UMDF OSR USB Sample Walk-through Requests and Queue Usage in the sample driver (srcumdfusbdriver) Callback locking constraint used (CMy. Device: : Initialize in Device. cpp) Dispatch type used (CMy. Queue: : Initialize in Queue. cpp) Queue callbacks used (CMy. Queue in Queue. h and Queue. cpp)

File Objects

File Objects

File Object represents open connection to device It is the session context for I/O

File Object represents open connection to device It is the session context for I/O All requests associated with a File Object in UMDF KMDF and WDM requests sometimes don’t have one File object for a request obtained using IWDFIo. Request: : Get. File. Object Trailing name used by client while opening connection is available via IWDFFile: : Get. File. Name

File Object (con’t) Device File 1 Request 2 File 2 Request 1 Request 2

File Object (con’t) Device File 1 Request 2 File 2 Request 1 Request 2

File Object Lifetime File Object’s lifetime spans Create: File Object gets created in response

File Object Lifetime File Object’s lifetime spans Create: File Object gets created in response to a connection being opened Cleanup: Notification of connection being torn down and that Close is pending Close: All I/O pertaining to this File Object has now ceased. File Object is now disposed. File Object is created and destroyed by the Framework All I/O operations happen in the context of File object i. e. , they happen between Create and Close These operations are: Read / Write / Device. Io. Control

File Object Lifetime Illustrated Example of I/O sequence between App and Driver Application h.

File Object Lifetime Illustrated Example of I/O sequence between App and Driver Application h. File = Create. File(… … Async/Sync Read/Write/Io. Ctl … Close. Handle(h. File); Driver Create Request … Read/Write/Io. Ctl Requests … Cleanup … Any remaining Requests drain … Close

Cleanup Handling in Driver Cleanup received when client closes connection Notification for driver to

Cleanup Handling in Driver Cleanup received when client closes connection Notification for driver to flush I/O for File Object Cancel or complete outstanding I/O as soon as possible Close will not come until all I/O is finished Cleanup is a “critical” operation in UMDF Cannot fail, subject to timeout Cleanup is not the end of I/O operations That’s the Close Request I/O received after a Cleanup should be cancelled/completed immediately

UMDF OSR USB Sample Walk-through File usage in the sample driver (srcumdfusbdriver) (Queue. cpp)

UMDF OSR USB Sample Walk-through File usage in the sample driver (srcumdfusbdriver) (Queue. cpp) CMy. Queue: : On. Read CMy. Queue: : On. Create. File CMy. Queue: : On. Cleanup. File CMy. Queue: : On. Close. File

Driver Layering

Driver Layering

Driver Layering UMDF supports driver layering Multiple drivers build a device stack “Function” driver

Driver Layering UMDF supports driver layering Multiple drivers build a device stack “Function” driver provides core device behavior “Filter” drivers modify aspects of device behavior Filter is a property set at device creation time All Framework Objects are per layer Each layer works only with its own objects e. g. , each layer gets a Request object to complete Driver sends request to next layer using I/O Target Represents the next driver in the stack That driver may be in user mode or kernel mode

Driver Layering Diagram Framework Device Queue File Request Framework Device Stack Queue File Request

Driver Layering Diagram Framework Device Queue File Request Framework Device Stack Queue File Request

Request Completion When Driver receives a Request it can Complete the Request synchronously Forward

Request Completion When Driver receives a Request it can Complete the Request synchronously Forward it to an I/O Target or an I/O Queue Hold on to it to complete later Driver must complete a Request it receives e. g. , while forwarding request to I/O Target Driver must register request-completion-callback object Framework invokes callback when target completes request Callback must complete request or arrange for completion UM IRP not complete until all layers complete their Request objects Completion callback is not a device level event Runs outside driver’s callback locking constraints

Request Completion Illustrated Request Completion Routine Request

Request Completion Illustrated Request Completion Routine Request

I/O Target

I/O Target

I/O Target Request I/O Queue Driver I/O Target Complete

I/O Target Request I/O Queue Driver I/O Target Complete

I/O Target Framework Object Provides a way to send requests to another device Local

I/O Target Framework Object Provides a way to send requests to another device Local I/O Target represents: The next device in the stack Another UM Driver, or the KM portion of the stack Driver doesn’t need to care which it is Remote I/O Target represents Some other UM or KM device stack Need feedback to prioritize this for Longhorn I/O Target is responsible for Sending I/O request to lower device Detecting completion and invoking callback interface

Local I/O Target Application Device I/O Target User Mode Kernel Mode Up Device Down

Local I/O Target Application Device I/O Target User Mode Kernel Mode Up Device Down Device Stack Reflector

I/O Target Functionality State based I/O handling Driver can start and stop the I/O

I/O Target Functionality State based I/O handling Driver can start and stop the I/O target In Response to a Pn. P Transition For any driver specific reason (e. g. , reconfigure after reset) Supports two I/O modes: Synchronous for short-term operations Asynchronous with callback for long-term operations Supports request timeout Outstanding request is cancelled when timeout expires Tracks sent requests for the driver Allows automatic purge or flush on I/O target stop Coordinates completion and cancellation

Bridging UM and KM stacks I/O Target provides bridge between KM and UM drivers

Bridging UM and KM stacks I/O Target provides bridge between KM and UM drivers Bottom-most I/O Target sends requests to kernel-mode stack Driver could also “escape” to the Platform API Send I/O using Win 32 File I/O API directly Advantages of using I/O Target Handles complexity of coordinating completion, cancellation and cleanup Allows for filtering and layered stacks transparently Allows routing of request to kernel mode in mode neutral way Offers rich functionality In Beta 1 Bottom-most I/O Target uses Win 32 File I/O API internally No way to use specific API (e. g. , Win. USB) Makes the escape necessary in such cases

UMDF OSR USB Sample Walk-through I/O Target usage in the sample filter (srcumdfusbfilter) Obtaining

UMDF OSR USB Sample Walk-through I/O Target usage in the sample filter (srcumdfusbfilter) Obtaining default I/O Target (CMy. Queue: : Initialize in Queue. cpp) Forwarding request down the stack (CMy. Queue: : On. Write in Queue. cpp) (CMy. Queue: : Forward. Request in Queue. cpp)

Request Cancellation

Request Cancellation

Request Cancellation Application cancel a request at any time by Using Cancel. Io[Ex] API

Request Cancellation Application cancel a request at any time by Using Cancel. Io[Ex] API Exiting application, etc. Higher layer driver cancel sent requests Cancel tells driver to complete request soon But not necessarily immediately Driver should abort any long operations Short synchronous requests can just be allowed to complete normally Cancel is a critical operation Cannot be failed, subject to timeout, etc… Cancellation is part of good user experience

Cancellation Overview Request Owner can register a cancel callback Cancel callback follows locking constraints

Cancellation Overview Request Owner can register a cancel callback Cancel callback follows locking constraints On Cancel: Request’s internal state is marked as cancelled Any callback registered after this will run immediately Registered cancel callback is cleared then invoked In the cancellation callback Owner arranges to cancel and complete request Remove callback before transferring ownership e. g. , when forwarding or completing the Request

Request Ownership Request ownership starts with I/O Queue Request ownership moves from: Queue to

Request Ownership Request ownership starts with I/O Queue Request ownership moves from: Queue to Driver – Driver receives the Request Driver to Queue – Driver forwards Request to Queue Driver to I/O Target – Driver forwards Request to I/O Target Queue or I/O Target handle cancellation when they own request I/O Target notifies you through completion callback Driver must handle cancel when it owns request If it holds on to the request for a long time

Cancellation Handling in Driver When driver receives a Request, it may: Complete it soon

Cancellation Handling in Driver When driver receives a Request, it may: Complete it soon Shortly send it to I/O Target Queue it back to Framework I/O Queue Hold on to it (not using Framework I/O Queue) Do (potentially) lengthy sync/asynch processing Driver needs to handle cancellation only in the last two cases

Cancellation Handling in Driver (con’t) Driver may register a cancel notification callback void IWDFIo.

Cancellation Handling in Driver (con’t) Driver may register a cancel notification callback void IWDFIo. Request: : Mark. Cancelable( IRequest. Callback. Cancel* p. Cancel. Callback ); In callback it should cancel/complete the request As soon as possible Unregister callback when transferring ownership Before sending request to I/O target or completing it HRESULT IWdf. Io. Request: : Unmark. Cancelable(); Failure return value indicates request has been canceled Cancel routine has run or will run soon Owner must ensure Request is completed only once

Cancellation Illustrated Let us take the example of OSR USB Driver This driver uses

Cancellation Illustrated Let us take the example of OSR USB Driver This driver uses device level locking It submits I/O requests to Win. USB The internal completion routine manually uses device level lock Request state is stored in Request context There are the following possibilities: 1. Request completes without cancellation 2. Request is cancelled 2 a. Cancel callback runs before completion callback 2 b. Cancel callback runs after completion callback The driver makes sure that: Request is completed only once Request is not completed until both completion and cancellation callback are done with it

Cancellation Illustrated (1) On. Read* … Req->Mark. Cancelable … Win. USB_Read. Pipe … On.

Cancellation Illustrated (1) On. Read* … Req->Mark. Cancelable … Win. USB_Read. Pipe … On. Cancel* … if (ctx->state == Request. Completed) { Complete. Request } else { Cancel. Io. Ex ctx->state = Cancel. Invoked; } * Invoked under Device. Lock On. USBRead. Complete … Device. Lock->Acquire. Lock(); if (Req->Unmark. Cancelable()) { Device. Lock->Release. Lock(); Complete. Request } else { if (ctx->state == Cancel. Invoked) { Device. Lock->Release. Lock(); Complete. Request } else { ctx->state = Request. Completed; Device. Lock->Release. Lock(); } }

Cancellation Illustrated (2 a) On. Read* … Req->Mark. Cancelable … Win. USB_Read. Pipe …

Cancellation Illustrated (2 a) On. Read* … Req->Mark. Cancelable … Win. USB_Read. Pipe … On. Cancel* … if (ctx->state == Request. Completed) { Complete. Request } else { Cancel. Io. Ex ctx->state = Cancel. Invoked; } * Invoked under Device. Lock On. USBRead. Complete … Device. Lock->Acquire. Lock(); if (Req->Unmark. Cancelable()) { Device. Lock->Release. Lock(); Complete. Request } else { if (ctx->state == Cancel. Invoked) { Device. Lock->Release. Lock(); Complete. Request } else { ctx->state = Request. Completed; Device. Lock->Release. Lock(); } }

Cancellation Illustrated (2 b) On. Read* … Req->Mark. Cancelable … Win. USB_Read. Pipe …

Cancellation Illustrated (2 b) On. Read* … Req->Mark. Cancelable … Win. USB_Read. Pipe … On. Cancel* … if (ctx->state == Request. Completed) { Complete. Request } else { Cancel. Io. Ex ctx->state = Cancel. Invoked; } * Invoked under Device. Lock On. USBRead. Complete … Device. Lock->Acquire. Lock(); if (Req->Unmark. Cancelable()) { Device. Lock->Release. Lock(); Complete. Request } else { if (ctx->state == Cancel. Invoked) { Device. Lock->Release. Lock(); Complete. Request } else { ctx->state = Request. Completed; Device. Lock->Release. Lock(); } }

UMDF OSR USB Sample Walk-through Cancellation walk-through in the sample driver (srcumdfusbdriver) (Queue. cpp)

UMDF OSR USB Sample Walk-through Cancellation walk-through in the sample driver (srcumdfusbdriver) (Queue. cpp) CMy. Queue: : On. Read CMy. Queue: : On. Cancel CMy. Queue: : Completion. Thread

Putting It Together You’ve seen the following portions of the sample: Driver (Driver. cpp)

Putting It Together You’ve seen the following portions of the sample: Driver (Driver. cpp) CMy. Driver: : On. Device. Add Device (Device. cpp) CMy. Device: : On. Prepare. Hardware CMy. Device: : On. Release. Hardware Queue (Queue. cpp) CMy. Queue: : On. Create. File CMy. Queue: : On. Cleanup. File CMy. Queue: : On. Read / CQueue: : On. Write CMy. Queue: : On. Cancel CMy. Queue: : Completion. Thread

Call to Action Install the Windows Driver Kit Join the WDF Beta Program At

Call to Action Install the Windows Driver Kit Join the WDF Beta Program At http: //beta. microsoft. com Guest ID: Guest 4 WDF Evaluate UMDF for your driver projects Consider development time, customer support for system crashes, etc. Send Us Feedback – We want to know If UMDF will meet your needs What stops you from writing your drivers with UMDF

Additional Resources Email umdffdbk @ microsoft. com Web Resources: WDF Information: http: //www. microsoft.

Additional Resources Email umdffdbk @ microsoft. com Web Resources: WDF Information: http: //www. microsoft. com/whdc/driver/wdf/default. mspx Windows Debugger: http: //www. microsoft. com/whdc/devtools/debugging/default. mspx External Resources “Introduction to the Windows Driver Foundation: How To Develop Device Drivers Using the Kernel Mode Driver Framework” from OSR Press Release date is September 2005 Focuses on KMDF but provides general WDF information as well

© 2005 Microsoft Corporation. All rights reserved. This presentation is for informational purposes only.

© 2005 Microsoft Corporation. All rights reserved. This presentation is for informational purposes only. Microsoft makes no warranties, express or implied, in this summary.