Windows Kernel I/O APIs

This section delves into the core Application Programming Interfaces (APIs) that form the backbone of input/output operations within the Windows kernel. Understanding these APIs is crucial for developing device drivers, system services, and high-performance I/O components.

I/O System Fundamentals

The Windows I/O system is a hierarchical and layered architecture designed for flexibility and extensibility. It manages communication between user-mode applications and hardware devices through a series of components, including drivers, the I/O Manager, and various kernel objects.

  • Device Drivers: Software components that interface directly with hardware devices.
  • I/O Manager: A central kernel component responsible for coordinating I/O operations, managing IRPs, and interacting with drivers.
  • I/O Request Packets (IRPs): The primary mechanism for passing I/O requests from the I/O Manager to device drivers.
  • Device Objects: Kernel objects representing devices, used by the I/O Manager and drivers to track and control devices.

Device Drivers

Drivers are the kernel-mode components that enable the operating system to communicate with specific hardware. They are typically developed using the Windows Driver Model (WDM) or Windows Driver Foundation (WDF).

Types of Drivers

  • Bus Drivers: Manage devices attached to a specific type of bus (e.g., PCI, USB).
  • Function Drivers: Provide the primary interface to a device for applications.
  • Filter Drivers: Intercept I/O requests to modify or extend device behavior.
  • Class Drivers: Provide a generic interface for a class of devices (e.g., disk drives, printers).

I/O Request Packets (IRPs)

IRPs are data structures used by the I/O Manager to convey I/O requests to drivers. Each IRP contains information about the type of operation requested, the associated device, and any associated data buffers.

Common IRP Major Functions

  • IRP_MJ_CREATE: Opening a handle to a device.
  • IRP_MJ_READ: Reading data from a device.
  • IRP_MJ_WRITE: Writing data to a device.
  • IRP_MJ_DEVICE_CONTROL: Sending custom I/O control codes to a device.
  • IRP_MJ_CLOSE: Closing a handle to a device.
  • IRP_MJ_CLEANUP: Flushing pending I/O for a handle.
  • IRP_MJ_QUERY_INFORMATION: Querying device properties.
  • IRP_MJ_SET_INFORMATION: Setting device properties.

Drivers process IRPs by implementing I/O dispatch routines for each relevant major function code.

Device Objects

A DEVICE_OBJECT structure represents a physical or logical device. It contains information used by the I/O Manager and drivers to manage the device, such as queues for IRPs and device-specific extensions.

  • Functional Device Object (FDO): Represents the primary instance of a device.
  • Filter Device Object (PDO): Represents a filter that sits above or below an FDO.
  • Physical Device Object (PDO): Represents the hardware device itself, managed by a bus driver.

The I/O Manager

The I/O Manager is a critical subsystem within the Windows kernel responsible for:

  • Creating and managing IRPs.
  • Routing IRPs to the appropriate drivers.
  • Managing I/O queues for devices.
  • Handling asynchronous I/O operations.
  • Interacting with memory management and process management subsystems.

Key Kernel-Mode I/O APIs

Developers working with kernel-mode I/O will frequently use the following APIs:

IoCreateDevice

Creates a device object for a driver.

NTSTATUS IoCreateDevice(
  IN PDRIVER_OBJECT DriverObject,
  IN ULONG DeviceExtensionSize,
  IN PUNICODE_STRING DeviceName OPTIONAL,
  IN DEVICE_TYPE DeviceType,
  IN ULONG DeviceCharacteristics,
  IN BOOLEAN Exclusive,
  OUT PDEVICE_OBJECT *DeviceObject
);

IoCreateSymbolicLink

Creates a symbolic link for a device object, allowing user-mode applications to access it via a well-known name.

NTSTATUS IoCreateSymbolicLink(
  IN PUNICODE_STRING SymbolicLinkName,
  IN PUNICODE_STRING DeviceName
);

IoDeleteDevice

Deletes a previously created device object.

VOID IoDeleteDevice(
  IN PDEVICE_OBJECT DeviceObject
);

IoWriteErrorLogEntry

Writes an error entry to the system's event log.

NTSTATUS IoWriteErrorLogEntry(
  IN PVOID IoObject,
  IN ULONG UniqueErrorValue,
  IN ...
);

IoAllocateIrp

Allocates an I/O Request Packet (IRP).

PIRP IoAllocateIrp(
  IN CCHAR StackSize,
  IN BOOLEAN ChargeQuota
);

IoFreeIrp

Frees a previously allocated IRP.

VOID IoFreeIrp(
  IN PIRP Irp
);

IoForwardIrpSynchronously

Forwards an IRP to the next lower driver in the stack and waits for completion.

NTSTATUS IoForwardIrpSynchronously(
  IN PDEVICE_OBJECT DeviceObject,
  IN PIRP Irp
);

IoStartNextPacket

Starts processing the next IRP in a device's I/O queue.

VOID IoStartNextPacket(
  IN PDEVICE_OBJECT DeviceObject,
  IN BOOLEAN WaitingForIo
);

IoCompleteRequest

Marks an IRP as complete and potentially wakes up threads waiting for its completion.

VOID IoCompleteRequest(
  IN PIRP Irp,
  IN IO_STATUS_BLOCK_IO_STATUS IoStatus
);