Recent from talks
Nothing was collected or created yet.
IRQL (Windows)
View on WikipediaAn Interrupt Request Level (IRQL) is a hardware-independent means with which Windows prioritizes interrupts that come from the system's processors. On processor architectures on which Windows runs, hardware generates signals that are sent to an interrupt controller. The interrupt controller sends an interrupt request (or IRQ) to the CPU with a certain priority level, and the CPU sets a mask that causes any other interrupts with a lower priority to be put into a pending state, until the CPU releases control back to the interrupt controller. If a signal comes in at a higher priority, then the current interrupt will be put into a pending state; the CPU sets the interrupt mask to the priority and places any interrupts with a lower priority into a pending state until the CPU finishes handling the new, higher priority interrupt.[1]
Windows maps not only hardware interrupt levels to its internal interrupt table but also maps software interrupts. The mappings in this table are called Interrupt Request Levels, or IRQLs, and a separate IRQL is kept for each processor in a multiprocessor system. The IRQL values are specific to the x86, IA64 and AMD64 processor architectures that Windows can run on, though theoretically they can support other CPUs that use a similar interrupt scheme (such as the DEC Alpha and MIPS, which were supported briefly on early versions of Windows). This means that APCs (asynchronous procedure calls), user threads and kernel mode operations can be interrupted, and the system must run them at an IRQL lower than the thread scheduler (or "dispatcher").[2]
See also
[edit]References
[edit]- ^ Russinovich, Mark (October 31, 1997), "Inside NT's Interrupt Handling", Windows IT Pro, Penton Media, archived from the original on September 13, 2016, retrieved April 26, 2016
- ^ Scheduling, Thread Context, and IRQL, Microsoft, April 26, 2016, pp. 6–7, archived from the original on October 22, 2016, retrieved April 26, 2016
IRQL (Windows)
View on GrokipediaOverview
Definition and Core Concept
In the Windows NT kernel, the Interrupt Request Level (IRQL) is an integer value that represents the hardware priority at which a processor operates at any given time, serving as a fundamental mechanism for managing interrupt processing and synchronization. This value ranges from 0 (the lowest priority) to 31 on x86 architectures or to 15 on x64 architectures, allowing the kernel to control the execution context of driver code and ensure orderly handling of hardware events.[1] IRQL functions as an abstraction layer over underlying hardware interrupt mechanisms, enabling portable interrupt handling across diverse processor types without requiring drivers to directly interface with architecture-specific details. By mapping hardware priorities to these standardized integer levels, the kernel facilitates consistent behavior in multiprocessor environments and supports the development of device drivers that operate reliably on both x86 and x64 systems. This abstraction is integral to the kernel's design, decoupling software logic from low-level hardware variations.[1] A core operational rule of IRQL is preemption based on priority: code executing at a higher IRQL can preempt code at a lower IRQL, while interrupts at or below the current IRQL are masked to prevent interference and maintain system stability. This ensures that high-priority hardware events, such as critical device interrupts, are handled promptly without disruption from lower-priority activities. IRQL originated in the Windows NT kernel with version 3.1, released on July 27, 1993, where it was established as a key kernel-mode synchronization primitive to coordinate access to shared resources in a preemptive, multitasking environment.[1][4]Purpose in the Windows Kernel
In the Windows kernel, IRQL plays a critical role in preventing race conditions by serializing access to shared resources through elevated priority levels. When the IRQL is raised, interrupts at or below that level are masked, ensuring that only the current code path executes without interference from lower-priority interrupts or threads. This mechanism is particularly vital in kernel-mode environments where multiple drivers and system components compete for resources, as it enforces mutual exclusion without relying solely on software locks. For instance, synchronization primitives like spin locks leverage IRQL elevation to protect critical sections, guaranteeing that shared data structures remain consistent during concurrent access.[1][5] IRQL integrates closely with the kernel scheduler to maintain atomicity in operations that must complete without interruption or preemption. At elevated IRQLs such as DISPATCH_LEVEL or higher, the scheduler is effectively blocked from dispatching threads or servicing lower-priority interrupts, allowing short, non-blocking code sequences to execute atomically on the processor. This prevents partial updates to kernel structures that could otherwise lead to inconsistencies, especially in interrupt-driven scenarios where timing is unpredictable. By temporarily suspending normal scheduling, IRQL ensures that high-priority kernel tasks, like handling hardware events, proceed without yielding control, thereby upholding the integrity of system operations.[1][5] IRQL contributes significantly to overall system stability by imposing strict rules on memory access and driver routine execution within the kernel. At IRQLs greater than APC_LEVEL, access to pageable memory is prohibited because page faults are disabled, avoiding potential deadlocks or crashes that could occur if the kernel attempted to swap in pages during non-preemptible code. Driver routines operating at raised IRQLs must adhere to these constraints, limiting their scope to non-pageable code and avoiding blocking calls, which the kernel enforces through bug checks like IRQL_NOT_LESS_OR_EQUAL if violated. This layered enforcement model promotes robust driver development and minimizes the risk of kernel panics in a multi-threaded, interrupt-heavy environment.[1] Since Windows 10, the core IRQL framework has seen no major architectural changes, maintaining its foundational role in kernel operations across subsequent versions including Windows 11. However, Microsoft has enhanced verification tools to improve compliance, with Static Driver Verifier incorporating advanced rules like IrqlDispatch and IrqlPsPassive to statically analyze driver code for IRQL violations during development. These tools help detect potential stability issues early, ensuring that drivers conform to IRQL requirements without altering the underlying mechanism.[6][7]IRQL Levels
Software-Defined Levels
In the Windows kernel, software-defined Interrupt Request Levels (IRQLs) represent predefined priority levels primarily used for scheduling and synchronization in kernel-mode operations, distinct from hardware-mapped levels associated with device interrupts. These levels range from 0 to 2 and control aspects such as preemption, paging, and Asynchronous Procedure Call (APC) delivery, ensuring predictable execution in multiprocessor environments.[1][8] The lowest software IRQL is PASSIVE_LEVEL, defined as 0 in kernel headers such asntddk.h. This level serves as the default for most kernel-mode code, including driver entry points, dispatch routines, and worker threads. At PASSIVE_LEVEL, threads are fully preemptible, paging operations are permitted, and normal APCs can be delivered, allowing the kernel to suspend execution for higher-priority tasks or asynchronous events without masking any interrupts.[1][8][9]
The intermediate level, APC_LEVEL (1), is specifically associated with the execution of special kernel-mode APCs. It blocks delivery of normal APCs—both user- and kernel-mode—while permitting special kernel APCs, which preempt lower-priority code but maintain thread context. Paging remains allowed, and memory allocations from the paged pool are permitted. Interrupts at APC_LEVEL or below are masked to prevent interference during these asynchronous operations. This level acts as a bridge between fully preemptible execution and higher-priority non-preemptible code.[1][10][8][11]
At DISPATCH_LEVEL (2), the kernel executes Deferred Procedure Calls (DPCs) and thread dispatchers in a non-preemptible manner, masking interrupts at DISPATCH_LEVEL and APC_LEVEL to ensure atomicity. Paging and waiting on dispatcher objects are prohibited, and most APCs are blocked, limiting available kernel support routines to those designed for non-paged execution. This level is critical for time-sensitive kernel scheduling, where device, clock, or power-failure interrupts may still occur but higher software operations are deferred.[1][12][8]
| IRQL Level | Numeric Value | Primary Associations | Key Permissions/Blocks |
|---|---|---|---|
| PASSIVE_LEVEL | 0 | Default kernel code, dispatch routines, worker threads | Allows preemption, paging, APC delivery; blocks none |
| APC_LEVEL | 1 | Special kernel APCs | Allows paging; blocks normal APCs |
| DISPATCH_LEVEL | 2 | DPCs, thread dispatching | Blocks paging, waiting, most APCs; non-preemptible |
#define PASSIVE_LEVEL [0](/page/0)), enabling developers to reference them directly in code. The KeGetCurrentIrql routine returns the current IRQL as an integer value (type KIRQL), allowing drivers to query and adapt to the execution context without hardcoding numerics.[13][8]
Hardware Interrupt Levels
Hardware interrupt levels, also known as Device IRQLs (DIRQLs), are assigned to physical hardware devices in the Windows kernel to prioritize interrupt processing based on device criticality. These levels range from 3 to 15 on x64 architectures, constrained by the 16 total IRQLs available (0 through 15) and modern hardware limitations such as APIC vector handling.[14] On legacy x86 systems, DIRQLs can extend up to 31, utilizing the full 32 IRQLs (0 through 31) supported by the architecture.[14] The mapping of hardware Interrupt Requests (IRQs) to specific DIRQLs is managed by the Hardware Abstraction Layer (HAL), which abstracts platform-specific details and ensures consistent behavior across systems.[14] Bus drivers report interrupt resources to the Plug and Play manager during device enumeration, and the HAL assigns DIRQLs via functions like HalpGetSystemInterruptVector, often influenced by ACPI tables or device priority configurations stored in the registry for certain legacy setups.[14] Higher-priority devices, such as system clock timers, are typically assigned elevated DIRQLs like 12 to 15 to guarantee low-latency handling, while lower-priority peripherals use levels closer to 3.[14][1] When the processor operates at a specific DIRQL, all interrupts at that level or lower are masked on the current core, preventing preemption until the IRQL is lowered, which ensures atomic execution for time-sensitive operations.[1][14] Only higher-DIRQL interrupts, such as those from critical hardware like power failure signals, can interrupt the current context.[1] Architectural differences in DIRQL handling stem from efficiency optimizations in x64, where the consolidated 16-level scheme reduces overhead in interrupt vector management compared to the expansive 32 levels on x86, a design that has remained stable since Windows Vista to support scalable multiprocessing.[14] On x64, DIRQL computation often involves dividing the interrupt vector by 16, simplifying mapping while maintaining priority distinctions.[14]Managing IRQL
Raising and Lowering Mechanisms
In the Windows kernel, the Interrupt Request Level (IRQL) can only be raised or lowered by the executing thread on the current processor, enforcing a strict stack discipline where nested raises accumulate and must be reversed in last-in-first-out order to restore the original level.[1] Raising IRQL to a value lower than or equal to the current level triggers a fatal system error, while lowering must precisely match the previously raised value; any deviation, such as lowering to an incorrect level, results in a bug check.[1] Raising the IRQL disables all interrupts at or below the new level on the current processor, preventing preemption by lower-priority interrupts and ensuring atomic execution of critical sections, though higher-level hardware interrupts remain enabled.[1] Additionally, at IRQL of DISPATCH_LEVEL (2) or higher, access to pageable memory is blocked, as page faults are not permitted at these elevated levels; any attempt to access paged pool or generate a page fault results in a bug check, such as 0xA (IRQL_NOT_LESS_OR_EQUAL) or 0xD1 (DRIVER_IRQL_NOT_LESS_OR_EQUAL).[3][15] The lowering process occurs either explicitly through kernel mechanisms or automatically upon exit from routines that raised the IRQL, restoring the prior level and re-enabling masked interrupts.[1] Improper lowering, including attempts by a different thread or to an unintended level, invokes bug checks to prevent system instability.[3] Due to IRQL being a per-processor attribute, changes affect only the executing CPU, which in multiprocessor systems can lead to serialized access and performance implications when coordinating across processors.[1][16]Associated Kernel APIs
The primary kernel-mode APIs for managing Interrupt Request Levels (IRQLs) in the Windows operating system enable drivers to query the current IRQL and adjust it to synchronize access to shared resources while adhering to preemption rules that prevent lower-priority code from interrupting critical sections.[1] These functions are defined in the Windows Driver Kit (WDK) headers such aswdm.h and are available starting from Windows 2000.[17]
The KeRaiseIrql routine raises the processor's IRQL to a specified value, thereby masking interrupts at or below that level on the current processor to ensure uninterrupted execution.[17] Its syntax is:
VOID KeRaiseIrql(
[in] KIRQL NewIrql,
[out] PKIRQL OldIrql
);
VOID KeRaiseIrql(
[in] KIRQL NewIrql,
[out] PKIRQL OldIrql
);
NewIrql parameter specifies the target IRQL (a KIRQL type, which is an unsigned 8-bit integer representing levels from 0 to 31), while OldIrql is an output pointer that stores the previous IRQL value for later restoration.[17][1] The routine returns VOID and can be called from any IRQL, but the new level must not be lower than the current one to avoid a bug check.[17]
Complementing this, the KeLowerIrql routine restores the processor's IRQL to a previously saved value, unmasking interrupts as appropriate.[18] Its syntax is:
VOID KeLowerIrql(
[in] KIRQL NewIrql
);
VOID KeLowerIrql(
[in] KIRQL NewIrql
);
NewIrql must match the value obtained from a prior KeRaiseIrql call on the same processor; otherwise, it triggers a fatal error.[18] Like KeRaiseIrql, it returns VOID and can be invoked from any IRQL, provided the target is not higher than the current one.[18]
To query the current IRQL without modification, drivers use the KeGetCurrentIrql routine, which simply returns the active level on the current processor.[13] Its syntax is:
KIRQL KeGetCurrentIrql(VOID);
KIRQL KeGetCurrentIrql(VOID);
KIRQL value, allowing drivers to check the IRQL before performing operations that require specific priority levels.[13] It can be called from any IRQL.[13]
Related to IRQL management, certain spinlock acquisition routines implicitly handle IRQL by assuming the caller is already at an elevated level, avoiding unnecessary raises or lowers for performance.[5] For instance, the KeAcquireSpinLockAtDpcLevel macro acquires an executive spin lock without altering the IRQL, requiring the caller to be at or above DISPATCH_LEVEL (IRQL 2).[19] Its syntax is:
VOID KeAcquireSpinLockAtDpcLevel(
[in, out] PKSPIN_LOCK SpinLock
);
VOID KeAcquireSpinLockAtDpcLevel(
[in, out] PKSPIN_LOCK SpinLock
);
SpinLock parameter points to an initialized KSPIN_LOCK structure allocated from non-paged pool.[19] It returns VOID and must be paired with KeReleaseSpinLockFromDpcLevel, which releases the lock without changing the IRQL.[20] These routines are used at DISPATCH_LEVEL or higher to synchronize multiprocessor access efficiently.[20]
