Windows 98/Me Compatibility Notes
In addition to the horrible problem with KeWaitXxx functions described in an earlier sidebar and the fact that KeReadStateEvent isn’t supported, note the following additional compatibility issues between Windows 98/Me on the one hand and Windows 2000/XP on the other.
You cannot wait on a KTHREAD object in Windows 98/Me. Attempting to do so crashes the system because the thread object doesn’t have the fields necessary for VWIN32 to wait on it.
DISPATCH_LEVEL in a WDM driver corresponds to what is called “interrupt time” in a VxD driver. Every WDM interrupt service routine runs at a higher IRQL, which means that WDM interrupts have higher priority than non-WDM interrupts. If a WDM device shares an interrupt with a VxD device, however, both interrupt routines run at the WDM driver’s DIRQL.
WDM driver code running at
PASSIVE_LEVEL
won’t be preempted in Windows 98/Me unless it blocks explicitly by waiting for a dispatcher object or implicitly by
Windows 98/Me is
Chapter 5
The I/O Request Packet
The operating system uses a data structure known as an I/O request packet, or IRP, to communicate with a kernel-mode device driver. In this chapter, I’ll discuss this important data structure and the means by which it’s created, sent,
This chapter is rather abstract, I’m afraid, because I haven’t yet talked about any of the concepts that surround specific types of I/O request packets (IRPs). You might, therefore, want to skim this chapter and refer back to it while you’re reading later chapters. The last major section of this chapter contains a cookbook, if you will, that
Data Structures
Two data structures are crucial to the handling of I/O
Structure of an IRP
Figure 5-1 illustrates the IRP data structure, with
MdlAddress
(
PMDL
) is the address of a memory descriptor list (MDL) describing the
Figure 5-1. I/O request packet data structure.
Flags ( ULONG ) contains flags that a device driver can read but not directly alter. None of these flags are relevant to a Windows Driver Model (WDM) driver.
AssociatedIrp (union) is a union of three possible pointers. The alternative that a typical WDM driver might want to access is named AssociatedIrp.SystemBuffer . The SystemBuffer pointer holds the address of a data buffer in nonpaged kernel-mode memory. For IRP_MJ_READ and IRP_MJ_WRITE operations, the I/O Manager creates this data buffer if the topmost device object’s flags specify DO_BUFFERED_IO . For IRP_MJ_DEVICE_CONTROL operations, the I/O Manager creates this buffer if the I/O control function code indicates that it should. (See Chapter 9.) The I/O Manager copies data sent by user-mode code to the driver into this buffer as part of the process of creating the IRP. Such data includes the data involved in a WriteFile call or the so-called input data for a call to DeviceIoControl . For read requests, the device driver fills this buffer with data; the I/O Manager later copies the buffer back to the user-mode buffer. For control operations that specify METHOD_BUFFERED , the driver places the so-called output data in this buffer, and the I/O Manager copies it to the user-mode output buffer.
IoStatus ( IO_STATUS_BLOCK ) is a structure containing two fields that drivers set when they ultimately complete a request. IoStatus.Status will receive an NTSTATUS code, while IoStatus.Information is a ULONG_PTR that will receive an information value whose exact content depends on the type of IRP and the completion status. A common use of the Information field is to hold the total number of bytes transferred by an operation such as IRP_MJ_READ that transfers data. Certain Plug and Play (PnP) requests use this field as a pointer to a structure that you can think of as the answer to a query.
RequestorMode will equal one of the enumeration constants UserMode or KernelMode , depending on where the original I/O request originated. Drivers sometimes inspect this value to know whether to trust some parameters.
PendingReturned
(
BOOLEAN
) is meaningful in a completion routine and indicates whether the
Cancel ( BOOLEAN ) is TRUE if IoCancelIrp has been called to cancel this request and FALSE if it hasn’t (yet) been called. IRP cancellation is a relatively complex topic that I’ll discuss fully later on in this chapter (in “Cancelling I/O Requests”).
CancelIrql
(
KIRQL
) is the interrupt request level (IRQL) at which the special cancel spin lock was
CancelRoutine ( PDRIVER_CANCEL ) is the address of an IRP cancellation routine in your driver. You use IoSetCancelRoutine to set this field instead of modifying it directly.
{% if main.adsdop %}{% include 'adsenceinline.tpl' %}{% endif %}
UserBuffer
(
PVOID
) contains the user-mode virtual address of the output buffer for an
IRP_MJ_DEVICE_CONTROL
request for which the control code specifies
METHOD_NEITHER
. It also holds the user-mode virtual address of the buffer for read and write requests, but a driver should usually specify one of the device flags
DO_BUFFERED_IO
or
DO_DIRECT_IO
and should therefore not usually need to access the field for reads or
Tail.Overlay
is a structure within a union that contains several
CurrentLocation ( CHAR ) and Tail.Overlay.CurrentStackLocation ( PIO_STACK_LOCATION ) aren’t documented for use by drivers because support functions such as IoGetCurrentIrpStackLocation can be used instead. During debugging, however, it might help you to realize that CurrentLocation is the index of the current I/O stack location and CurrentStackLocation is a pointer to it.
Figure 5-2. Map of the Tail union in an IRP.
The I/O Stack
Whenever any kernel-mode program creates an IRP, it also creates an associated array of IO_STACK_LOCATION structures: one stack location for each of the drivers that will process the IRP and sometimes one more stack location for the use of the originator of the IRP. (See Figure 5-3.) A stack location contains type codes and parameter information for the IRP as well as the address of a completion routine. Refer to Figure 5-4 for an illustration of the stack structure.
Figure 5-3. Parallelism between driver and I/O stacks.
NOTE
I’ll discuss the mechanics of creating IRPs a bit further on in this chapter. It helps to know right now that the
StackSize
field of a
DEVICE_OBJECT
indicates how many locations to reserve for an IRP sent to that device’s driver.
MajorFunction ( UCHAR ) is the major function code associated with this IRP. This code is a value such as IRP_MJ_READ that corresponds to one of the dispatch function pointers in the MajorFunction table of a driver object. Because the code is in the I/O stack location for a particular driver, it’s conceivable that an IRP could start life as an IRP_MJ_READ (for example) and be transformed into something else as it progresses down the stack of drivers. I’ll show you examples in Chapter 12 of how a USB driver changes the personality of a read or write request into an internal control operation to submit the request to the USB bus driver.
MinorFunction
(
UCHAR
) is a minor function code that further identifies an IRP
Figure 5-4. I/O stack location data structure.
Parameters (union) is a union of substructures, one for each type of request that has specific parameters. The substructures include, for example, Create (for IRP_MJ_CREATE requests), Read (for IRP_MJ_READ requests), and StartDevice (for the IRP_MN_START_DEVICE subtype of IRP_MJ_PNP ).
DeviceObject ( PDEVICE_OBJECT ) is the address of the device object that corresponds to this stack entry. IoCallDriver fills in this field.
FileObject ( PFILE_OBJECT ) is the address of the kernel file object to which the IRP is directed. Drivers often use the FileObject pointer to correlate IRPs in a queue with a request (in the form of an IRP_MJ_CLEANUP ) to cancel all queued IRPs in preparation for closing the file object.
CompletionRoutine
(
PIO_COMPLETION_ROUTINE
) is the address of an I/O completion routine installed
by the driver above the one to which this stack location corresponds.
You never set this field directly—instead, you call
IoSetCompletionRoutine
, which
Context ( PVOID ) is an arbitrary context value that will be passed as an argument to the completion routine. You never set this field directly; it’s set automatically from one of the arguments to IoSetCompletionRoutine .

The Windows 2000 Device Driver Book: A Guide for Programmers (2nd Edition)

Windows System Programming (4th Edition) (Addison-Wesley Microsoft Technology Series)

Developing Drivers with the Windows Driver Foundation (Pro Developer)

Windowsu00ae Internals: Including Windows Server 2008 and Windows Vista, Fifth Edition (Pro Developer)