Skip to main content

Crate irql

Crate irql 

Source
Expand description

Compile-time IRQL safety for Windows kernel drivers.

IRQL violations are caught at compile time using Rust’s type system — zero runtime cost, zero binary size overhead.

§Quick start

use irql::{irql, Dispatch, Passive};

#[irql(max = Dispatch)]
fn acquire_spinlock() { /* … */ }

#[irql(at = Passive)]
fn driver_entry() {
    call_irql!(acquire_spinlock());
}

§The #[irql()] attribute

FormMeaning
#[irql(at = Level)]Fixed entry point — known IRQL, no generic
#[irql(max = Level)]Callable from Level or below
#[irql(min = A, max = B)]Callable in the range [A, B]

max is required unless using at — it defines the ceiling that call_irql! relies on. min is optional and adds a floor constraint. at is mutually exclusive with min/max.

Works on functions, inherent impl blocks, and trait impl blocks.

§IRQL levels

ValueTypeDescription
0PassiveNormal thread execution; paged memory OK
1ApcAPC delivery
2DispatchDPC / spinlock level
3–26DirqlDevice interrupt levels
27ProfileProfiling timer
28ClockClock interrupt
29IpiInter-processor interrupt
30PowerPower failure
31HighHighest — machine check

Each level is a zero-sized marker type implementing IrqlLevel.

§The golden rule

IRQL can only stay the same or be raised, never lowered.

Attempting to call a lower-IRQL function produces a compile error:

use irql::{irql, Dispatch, Passive};

#[irql(max = Passive)]
fn passive_only() {}

#[irql(max = Dispatch)]
fn at_dispatch() {
    call_irql!(passive_only()); // ERROR: cannot lower IRQL
}

§IRQL-aware allocation (alloc feature)

Enable with irql = { features = ["alloc"] }.

Requires a nightly Rust compiler — depends on unstable allocator_api, vec_push_within_capacity, auto_traits, and negative_impls. Add a rust-toolchain.toml with channel = "nightly" to your project.

Pool allocations automatically use ExAllocatePool2 / ExFreePool from wdk-sys in WDM/KMDF driver builds. Outside a WDK build (e.g. testing), the global allocator is used as a fallback.

IrqlBox and IrqlVec enforce pool rules at compile time:

#[irql(max = Passive)]
fn example() -> Result<(), AllocError> {
    let data = call_irql!(IrqlBox::new(42))?;  // PagedPool (automatic)
    let val = call_irql!(data.get());

    let v = irql_vec![1, 2, 3]?;
    Ok(())
}

§FFI interop

IrqlBox provides raw pointer methods for passing allocations to kernel APIs and C callbacks:

let b = call_irql!(IrqlBox::new(data))?;
let ptr = b.into_raw();  // pass to kernel API
// later, reconstruct:
let b = unsafe { IrqlBox::<_, PagedPool>::from_raw(ptr) };

§Drop safety

Paged-pool containers (IrqlBox<T, PagedPool>, IrqlVec<T, PagedPool>) must not be dropped at Dispatch or above. This is enforced at compile time via SafeToDropAt* auto traits (enabled automatically with alloc). The #[irql] macro injects T: SafeToDropAt<Level> bounds on by-value parameters, so passing a paged-pool value (or any struct containing one) by value into code at Dispatch+ is a compile error.

References (&IrqlBox) are not gated — they don’t trigger a drop. Use IrqlBox::leak() or IrqlBox::into_raw() when you need to transfer ownership across an IRQL boundary.

§Safety

All checks are compile-time only. You must ensure:

  • Entry points (#[irql(at = …)]) match the actual runtime IRQL.
  • IRQL-raising operations (spinlocks, etc.) are properly modelled.

Structs§

Apc
IRQL level: Apc.
Clock
IRQL level: Clock.
Dirql
IRQL level: Dirql.
Dispatch
IRQL level: Dispatch.
High
IRQL level: High.
Ipi
IRQL level: Ipi.
Passive
IRQL level: Passive.
Power
IRQL level: Power.
Profile
IRQL level: Profile.

Traits§

IrqlCanLowerTo
The current IRQL is at or above Target.
IrqlCanRaiseTo
The current IRQL can be raised to Target.
IrqlFn
IRQL-safe analogue of Fn — callable multiple times via shared reference.
IrqlFnMut
IRQL-safe analogue of FnMut — callable multiple times via mutable reference.
IrqlFnOnce
IRQL-safe analogue of FnOnce — callable exactly once, consuming self.
IrqlLevel
Marker trait implemented by all IRQL level types.
SafeToDropAt
Self can be safely dropped at IRQL Level.

Attribute Macros§

irql
Compile-time IRQL constraint.