This document details the fundamental entry points for Windows drivers, specifically focusing on the I/O Subsystem. Understanding these points is crucial for developing robust and efficient kernel-mode drivers.
Every Windows driver must expose specific functions that the operating system kernel calls to manage the driver's lifecycle and operations. These functions serve as the interfaces between the driver and the I/O Manager. Key entry points include the driver's initialization routine, unload routine, and routines for handling I/O requests.
DriverEntryThis is the first function that the I/O Manager calls when it loads a device driver. It's the driver's primary initialization routine.
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath);DriverObject: A pointer to a DRIVER_OBJECT structure, which the I/O Manager allocates and initializes. The driver uses this structure to record information about itself.RegistryPath: A pointer to a UNICODE_STRING that specifies the path to the driver's parameters in the registry.STATUS_SUCCESS on successful initialization, or an appropriate NTSTATUS error code if initialization fails.DriverObject structure to handle various I/O requests (e.g., IRP_MJ_CREATE, IRP_MJ_READ).AddDeviceThis routine is called by the PnP Manager when a device controlled by the driver is enumerated and needs to be started. It's a critical part of Plug and Play driver development.
NTSTATUS AddDevice(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT PhysicalDeviceObject);DriverObject: A pointer to the driver's DRIVER_OBJECT.PhysicalDeviceObject: A pointer to the physical device object (PDO) representing the hardware device.STATUS_SUCCESS if a functional device object (FDO) was created and attached successfully, or an appropriate NTSTATUS error code.UnloadThis optional routine is called by the I/O Manager when the driver is unloaded from memory. It allows the driver to perform cleanup operations.
VOID Unload(PDRIVER_OBJECT DriverObject);DriverObject: A pointer to the driver's DRIVER_OBJECT.Drivers implement a set of dispatch routines to handle specific types of I/O Request Packets (IRPs) sent by the I/O Manager. These routines are assigned to members of the DriverObject structure, indexed by IRP major function codes.
Common dispatch routines include:
IRP_MJ_CREATE: Handles requests to open a device or file.IRP_MJ_CLOSE: Handles requests to close a device or file.IRP_MJ_READ: Handles read requests.IRP_MJ_WRITE: Handles write requests.IRP_MJ_DEVICE_CONTROL: Handles device-specific I/O control codes.IRP_MJ_PNP: Handles Plug and Play requests (e.g., start, stop, remove device).IRP_MJ_POWER: Handles power management requests.All I/O dispatch routines share a common signature:
NTSTATUS DispatchRoutine(PDEVICE_OBJECT DeviceObject, PIRP Irp);
DeviceObject: A pointer to the device object the IRP is intended for.Irp: A pointer to the IRP structure, containing all information about the I/O request.
// DriverEntry function excerpt
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) {
// ... initialization code ...
// Set up dispatch routines
DriverObject->MajorFunction[IRP_MJ_CREATE] = MyCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyCreateClose;
DriverObject->MajorFunction[IRP_MJ_READ] = MyRead;
DriverObject->MajorFunction[IRP_MJ_WRITE] = MyWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MyDeviceControl;
DriverObject->MajorFunction[IRP_MJ_PNP] = MyPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = MyPower;
// Assign the unload routine
DriverObject->DriverUnload = MyUnload;
// ... more initialization ...
return STATUS_SUCCESS;
}
// Example dispatch routine signature
NTSTATUS MyRead(PDEVICE_OBJECT DeviceObject, PIRP Irp) {
// Handle read request
// ...
return STATUS_SUCCESS; // or STATUS_PENDING, or an error code
}