Interrupts in Windows Drivers
Introduction
Interrupts are hardware signals that a device sends to the processor to indicate that it requires immediate attention. In Windows driver development, understanding and correctly handling interrupts is crucial for efficient device operation and system stability. This document provides a comprehensive overview of interrupts for Windows drivers.
Interrupt Requests (IRQLs)
Interrupts are assigned a priority level known as an Interrupt Request Level (IRQL). The system uses IRQLs to manage interrupt handling and ensure that higher-priority interrupts are processed before lower-priority ones. Understanding the different IRQLs is essential for correct synchronization and preventing race conditions.
- Passive Level: The lowest IRQL, used for user-mode operations and most system tasks.
- APC Level: Used for Asynchronous Procedure Calls.
- DISPATCH_LEVEL: Used for interrupt service routines (ISRs) and deferred procedure calls (DPCs). Code running at DISPATCH_LEVEL cannot be preempted by a thread that requires the processor.
- High-Level IRQLs: Reserved for critical system functions and hardware interrupts.
Interrupt Service Routines (ISRs)
When an interrupt occurs, the operating system calls the device's Interrupt Service Routine (ISR). The ISR is a piece of code written by the driver that runs at a high IRQL (typically DISPATCH_LEVEL) to quickly acknowledge the interrupt, determine the cause, and perform essential hardware-specific tasks.
A typical ISR performs the following actions:
- Acknowledge the interrupt to the hardware.
- Disable further interrupts from the device if necessary.
- Determine the cause of the interrupt (e.g., data ready, error).
- Perform minimal hardware interaction.
- Schedule deferred processing if more complex actions are required.
Handling Interrupts
Drivers register their ISRs with the operating system during driver initialization. This is typically done by calling the IoConnectInterrupt routine. This routine requires parameters such as the ISR function pointer, device context, interrupt vector, IRQL, and affinity.
// Example snippet (conceptual)
NTSTATUS IoConnectInterrupt(
PKINTERRUPT *InterruptObject,
PKSERVICE_ROUTINE ServiceRoutine,
PVOID ServiceContext,
PVOID SpinLock,
KIRQL Irql,
KIRQL SynchronizeIrql,
BOOLEAN InterruptServiceTaken
);
Deferring Processing
Since ISRs run at a high IRQL and must be fast, complex operations or operations that might block are handled by Deferred Procedure Calls (DPCs). The ISR typically programs a DPC object to be executed later at DISPATCH_LEVEL but at a lower IRQL than the ISR.
The DPC routine can safely:
- Process incoming data or complete outgoing data transfers.
- Update device state.
- Signal completion to I/O request packets (IRPs).
- Re-enable interrupts from the device.
Advanced Topics
- Message Signaled Interrupts (MSI/MSI-X): Modern hardware often supports MSI/MSI-X, which use memory-mapped writes instead of traditional interrupt lines. This can improve performance and scalability.
- Interrupt Affinity: Controlling which processors an interrupt can be delivered to.
- Interrupt Steering: Techniques for distributing interrupts across multiple cores.
- Synchronization: Using spin locks to protect shared data structures accessed by ISRs and DPCs.