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
);