UMDF From the perspective of the Windows I/O manager, the target of an I/O request must be a WDM device object. These objects reside in the kernel-mode address space and are not accessible to user-mode drivers. A key requirement for UMDF is a secure way to bridge the gap between user mode and kernel mode and to deliver the I/O requests to a user-mode driver. This requirement is handled by the following major elements of the UMDF infrastructure:
A kernel-mode driver-called the reflector-that represents UMDF drivers in the kernel-mode part of the device stack. The reflector manages communication to and from the UMDF host process, which runs in user mode.
A communication mechanism that allows requests to be sent across the user-mode/ kernel-mode boundary to the host process and back again.
Figure 4-2 shows the components that make up the UMDF infrastructure and the associated driver. Microsoft provides most of the components in this diagram. The primary exception is the UMDF driver or drivers and sometimes the lower device stack, which a hardware vendor might implement.
Figure 4-2: UMDF driver and infrastructure
Each UMDF driver operates as part of a device stack that manages a device. Part of the stack runs in user mode and part of the stack runs in kernel mode, as follows:
The upper part of the stack runs in user mode. This consists of a host process-Wudfhost-that loads the driver and framework DLLs. The host process also helps manage communication between the drivers in the UMDF stack and between the kernel-mode and user-mode components of the stack.
The lower part of the stack runs in kernel mode. This handles the actual interaction with the kernel subsystems and the device. In some cases, such as USB drivers, Microsoft provides the lower device stack. In other cases, the hardware vendors implement the lower device stack.
For some UMDF drivers, the sole purpose of the kernel-mode portion of the device stack is to add the device to the PnP manager's device tree. Examples of such drivers include software-only drivers and drivers for network-connected devices that use the Windows API to communicate with their devices.
The rest of this section provides a brief introduction to the components that make up the UMDF infrastructure, starting from the top of Figure 4-2.
Wudfhost hosts the components that comprise the user-mode part of the device stack and mediates communication between those components and the reflector. Each UMDF stack has its own host process. The following are the principal hosted components:
A UMDF stack This stack consists of one or more function or filter drivers. The UMDF stack has its own device objects and I/O request packets, which are related to the underlying WDM data structures. The UMDF stack handles I/O requests in much the same way as a kernel-mode stack, although the implementation details are different.
One or more instances of the framework One instance of the framework exists for each UMDF driver in the stack. The framework is a library that supports the UMDF object model and mediates communication between the drivers and the host process.
Wudfhost is a child of the driver manager process. Although it is not a Windows service, Wudfhost runs with the security credentials of a LocalService account.
Tip See "Service User Accounts" on MSDN for more information on LocalService and other accounts-online at http://go.microsoft.com/fwlink/?LinkId=82318.
Sometimes we use WUDF as the acronym, sometimes we use UMDF, and then sometimes KMDF is just WDF. It's an unfortunate side effect of when the KMDF and UMDF projects started. Originally there was just "WDF"-the Windows Driver Framework. Then the Windows User-Mode Driver Framework came along. For a while there was also a Windows Kernel-Mode Driver Framework. Finally we settled on KMDF and UMDF, but by that point the older acronyms were already cemented in the code base.
-Peter Wieland, Windows Driver Foundation Team, Microsoft
The driver manager is a Windows service that manages all UMDF host processes on the system. It creates host processes, maintains status information while the host processes are running, and shuts down host processes when they are no longer required. The driver manager is disabled until the first UMDF driver is installed.
The reflector is a kernel-mode driver that supports all UMDF drivers on the system. It manages communication between kernel-mode components such as kernel-mode device stacks and UMDF host processes. The reflector creates the following two device objects for each UMDF device stack on the system:
The Up device object This object is installed at the top of the device's kernel-mode device stack. It receives requests from the I/O manager, passes them to the UMDF host process for processing, and returns them to the I/O manager after they are completed.
The Down device object This object is a "side object" that is not installed in the kernel-mode device stack. It receives I/O requests from the UMDF host process after the drivers have processed the requests. The Down device object passes them to the lower device stack, which handles communication with the device. The host process also communicates with the Down device object for purposes such as creating a device interface or impersonating a client.
The reflector also creates another side object-a Control device object-that services all UMDF host processes on the system. The Control device object handles communication between the reflector and the UMDF host processes that is not related to I/O requests, such as managing the creation or shutdown of a host process.
There are a couple of simple examples that help explain this. When starting up a device stack, we needed the UMDF driver to be able to send I/O requests to the lower device stack. We couldn't talk to the lower device stack itself because the I/O manager won't let you open a device stack before it's started.
A similar issue happens with device removal. The PnP manager won't issue a remove request to a device stack until the last handle to it has been closed. But if we closed that handle, the user-mode driver wouldn't have been able to send commands to the device during removal.
We could have built an internal interface that would let us send I/O requests early, but that wouldn't work with ReadFile and WriteFile and would create a compatibility problem. The side object solves this problem quite elegantly. Because it's not in the device stack, we can open it whenever we want. The reflector blocks any I/O from non-host processes, so no one else can open or use the side object, and the driver can use the same APIs to access the object during start and remove that it would any other time.
-Peter Wieland, Windows Driver Foundation Team, Microsoft
UMDF drivers ultimately depend on an underlying kernel-mode device stack to handle the actual communication with the device. In cases such as USB drivers, the UMDF driver can use the kernel-mode device stack from Microsoft. Otherwise, the hardware vendor must provide lower drivers.
When the framework stops a driver because of a fatal error, it terminates only the driver host process; other processes and the system itself can continue. A great benefit of running in user mode is that a driver can access only its own address space, not the kernel address space. As a result, a fatal driver error does not affect kernel memory, so it crashes only the driver process, not the entire system.
When a UMDF driver fails, the reflector completes any outstanding I/O requests with an error status, and it sends a notification to any applications that have registered to receive such notices. Windows logs the failure and tries up to five times to restart this instance of the device. If the device cannot be restarted, the system disables the device and, if no handles are open to any device objects in the device stack, unloads the associated kernel drivers in the device stack.
Tip See "Handling Driver Failures" in the WDK for more information on how to handle fatal errors in UMDF drivers-online at http://go.microsoft.com/fwlink/?LinkId=79794.
An application opens communication with a UMDF driver by using the device interface to obtain the device's symbolic link name and then calling CreateFile to obtain a device handle. The application uses the handle to send I/O requests to the driver. The application is typically not aware that it is using a user-mode driver, because the procedure for obtaining a device handle and sending I/O requests to a device works exactly the same way for a UMDF driver as for a kernel-mode driver.
A typical UMDF I/O request, such as a read or device I/O control request, takes the following path:
An application calls a Windows function such as ReadFile or DeviceIoControl to send an I/O request to the device. Windows calls the appropriate kernel-mode I/O routine, which passes the request to the I/O manager.
The I/O manager creates an IRP and sends it to the reflector's Up device object, which passes the request to the driver's host process. The host process creates a "user-mode IRP" to represent the IRP in the user-mode part of the device stack.
The host process passes the user-mode IRP to the top instance of the framework in the device stack.
The framework uses the data from the user-mode IRP to create a framework I/O request object and passes it to the appropriate driver callback object.
The driver processes the I/O request and sends it to the driver's default I/O target, typically the next lower driver in the stack. This action passes the request back to the framework, which asks the host process to send the request to the next driver. The framework also stores a pointer to the request object, which allows the framework to determine later whether the driver registered a request completion callback.
If the stack has additional UMDF drivers, steps 3, 4, and 5 are repeated for each UMDF driver in succession until the request reaches a driver that can complete the request.
The host process sends the processed request to the reflector's Down device object, which creates a second IRP.
The Down device object passes the request to the lower device stack, which processes the request and communicates with the device as required. Eventually, a driver in the lower device stack completes the second IRP.
The Down device object returns the completed I/O request to the driver's host process. If any UMDF drivers have registered request completion callbacks, the framework calls them in order, starting from the bottom of the stack.
After the completion callbacks for all of the UMDF drivers are finished, the framework passes the completed I/O request to the reflector's Up device object and frees the user-mode IRP. The Up device object passes the request back to the I/O manager, which returns the results of the request to the application.