1. Windows I/O Overview
Before writing a driver—even a User Mode Driver—you must understand the basics of the Windows I/O architecture, as shown in Figure 1.
In this overview, we will discuss some of the major principles behind
the I/O system and define the most important terms.
As Figure 4.1
shows, Windows supports a layered I/O architecture. User mode
applications and services issue I/O requests through the Win32 API and
communicate with the user mode PnP manager to perform Plug and Play and
power activities. The Win32 API and user mode PnP manager, in turn,
communicate with the kernel mode I/O system, which includes the kernel
mode I/O manager, PnP manager, and power manager. The kernel mode I/O
system communicates with the Kernel Mode Drivers.
Drivers
are also layered. Most devices are driven by not one but by several
drivers, each layered atop the next. Together, the group of drivers that
operates a particular device is called the device stack (sometimes also
called the driver stack). At the bottom of the device stack is a bus
driver, which controls a bus and enumerates the devices that are
connected to the bus. Layered above the bus driver are filter drivers
and a function driver. The function driver is the primary driver for the
device and exposes the device interface to the I/O manager. Filter
drivers can be layered above or below the function driver and provide
additional features, such as encryption or security, or change the
behavior of a device. Each driver in the device stack is represented by a
device object. The device object is a data structure that contains
information about the driver and the device.
Drivers receive I/O, Plug and
Play, and power management requests in the form of I/O request packets
(IRPs). When the Windows I/O manager receives an I/O request, it
determines which device stack corresponds to the virtual file that is
specified in the request. It then packages the request into an IRP and
forwards it to the target device object. Plug and Play and power
management notifications are also packaged as IRPs, and drivers
communicate with other drivers by sending IRPs.
When
a driver receives an IRP, it takes whatever actions are required to
satisfy the request and then completes it. Sometimes, however, a driver
cannot satisfy an IRP by itself. If the driver cannot complete the IRP,
it typically passes the IRP down the device stack to the next driver and
optionally sets an I/O completion routine for callback when the request
is complete. Eventually, the IRP arrives at a driver that satisfies and
completes the request. When the request is complete, the I/O manager
calls any completion callback routines that drivers set as the request
traveled down the device stack. It calls these routines in the opposite
order in which they were set—that is, it “unwinds” back up the device
stack.
2. Brief COM Information
The UMDF interfaces are
defined in terms of COM. UMDF does not depend on the COM infrastructure
and run-time library. Instead, it uses only the COM programming pattern,
specifically the query-interface and reference-counting features. It
does not use the COM run-time loader.
The following is a brief overview on COM:
COM is based on a client-server model.
COM maintains reference counts for all of its objects.
COM objects expose interfaces, which support callable methods.
COM
interfaces are C++ abstract base classes. An interface contains one or
more methods that form the contract for any caller that wants to use the
class.
The
query-interface (QI) feature of COM enables a client to query a server
to determine whether the server supports a particular interface. UMDF
drivers can request notification of particular system events by exposing
callback interfaces. UMDF uses the QI feature to discover these
callback interfaces.
IUnknown is the fundamental COM interface, and every COM object supports it. IUnknown supports the QueryInterface, AddRef, and Release methods. The QueryInterface method enables other components to determine which interfaces the object supports. The AddRef and Release methods manage object lifetime.
The IClassFactory interface creates instances of class objects. UMDF calls DllGetClassObject to get a pointer to an IClassFactory interface in the driver and then uses the CreateInstance method of the IClassFactory interface to create an instance of the driver object.
When
COM returns an interface pointer to a driver, it takes out a reference
on the corresponding object. The driver should release this reference by
calling the object’s Release
method when it has finished using the object. Failing to release
references causes object leaks, which consume memory unnecessarily.
3. UMDF Architecture
A UMDF driver is a dynamic-link library (DLL) that runs as an in-process COM server. Figure 2 shows the components that are involved when a UMDF driver controls a device.
As Figure 2
shows, the User Mode Driver runs under the Host Process, which combines
with Kernel Mode Drivers (including the reflector) to form the device
stack for the device.
The following describes the preceding components in the figure according to the typical flow of an I/O request.
Application. The application issues I/O requests through the Win32 API, which in turn calls I/O routines in the Windows kernel.
Windows kernel.
The Windows kernel creates IRPs to represent the requests and forwards
them to the top of the kernel mode device stack for the target device.
Reflector. The
reflector is a Kernel Mode WDM Filter Driver that is installed at the
top of the kernel mode device stack for each device that is managed by a
UMDF driver. The reflector manages communication between the kernel
mode components and the User Mode Driver host process.
Driver manager.
The driver manager creates and shuts down all the driver host processes
and maintains status information about them. It also responds to
messages from the reflector. The driver manager runs as a Windows
service and is started during installation of the first device that is
managed by a UMDF driver. The driver manager must be running all the
time that any device controlled by a UMDF driver is installed on the
system. Microsoft provides the driver manager.
Host process.
The host process is the process in which the User Mode Driver runs. The
host process is a child process of the driver manager and runs in the
security credentials of a LocalService account, although it is not a
Windows service. The host process includes the following components:
The UMDF driver is an in-process COM component that controls the hardware from user mode.
UMDF
exposes the User Mode device-driver interface (DDI). UMDF is a DLL of
COM-style objects that support the presentation, flow, and management of
I/O and Plug and Play requests to the driver.
The
run-time environment dispatches I/O requests, loads the driver,
constructs and destroys the user mode device stack, manages a user mode
thread pool, and handles messages from the reflector and the driver
managers.
Kernel Mode Drivers. Additional Kernel Mode Drivers can service each device.