I/O Request Packets (IRPs)

I/O Request Packets (IRPs) are fundamental data structures used by the Windows operating system's I/O subsystem to communicate I/O operations between user-mode applications, the kernel, and device drivers. An IRP encapsulates all the information necessary to describe an I/O request, such as reading from or writing to a device, controlling a device, or querying device information.

What is an IRP?

An IRP is a dynamically allocated structure, typically defined by the IO_STACK_LOCATION structure within the larger IRP structure. Each driver in the I/O stack for a particular device receives a pointer to the same IRP. However, each driver typically uses its own IO_STACK_LOCATION within the IRP to store context specific to its processing of the I/O request.

Key Concept: IRPs are central to the Windows I/O model, enabling a layered and modular approach to device driver development.

IRP Structure and Key Fields

The IRP structure contains a variety of fields, but the most critical part for driver interaction is the array of IO_STACK_LOCATION structures.

IRP Flow and Processing

When an I/O operation is initiated (e.g., by a call to ReadFile or DeviceIoControl in user mode), the I/O Manager:

  1. Allocates an IRP structure.
  2. Initializes the IRP's IO_STACK_LOCATION for the highest-level driver in the device stack.
  3. Passes the IRP down the driver stack.
  4. Each driver in the stack processes the IRP, potentially modifying its own stack location and passing it to the next lower driver using IoCallDriver.
  5. Once the IRP reaches the lowest driver (often a port driver or the hardware abstraction layer), it is processed, and the device operation is performed.
  6. The IRP then propagates back up the stack. Each driver that receives the IRP on its way up can perform completion processing (e.g., setting the final status, freeing resources).
Note: Drivers are responsible for allocating and freeing IRPs for certain operations, but often the I/O Manager handles the initial allocation for standard I/O requests.

Common IRP Major Function Codes

The MajorFunction field in the IO_STACK_LOCATION identifies the type of operation. Some common codes include:

Driver Responsibility

Device drivers must implement dispatch routines for the IRP major function codes they support. These routines are typically pointed to by entries in the driver's dispatch table. The driver's dispatch routine examines the MajorFunction code to determine how to handle the request.


// Example of a driver's dispatch table entry (simplified)
NTSTATUS MyDriverDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
    // ... Get IoStackLocation ...
    PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);

    switch (irpStack->MajorFunction) {
        case IRP_MJ_READ:
            // Handle read request
            break;
        case IRP_MJ_WRITE:
            // Handle write request
            break;
        case IRP_MJ_DEVICE_CONTROL:
            // Handle device control request
            break;
        // ... other cases ...
        default:
            // Unhandled request
            Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
            IoCompleteRequest(Irp, IO_NO_INCREMENT);
            return Irp->IoStatus.Status;
    }
    // ... more processing or passing down ...
}
            

Understanding IRPs is crucial for developing robust and efficient Windows device drivers. Their well-defined structure and managed flow allow for complex I/O operations to be handled reliably across a wide range of hardware.