irql - Compile-time IRQL safety for Windows kernel drivers in Rust
I've been writing Windows kernel drivers in Rust and kept running into the same problem: IRQL violations. Call a paged function at DISPATCH_LEVEL? Blue screen. Drop paged-pool memory at elevated IRQL? Blue screen. These bugs hide in deep call chains and only surface under the right timing.
The traditional defense is PAGED_CODE() -- a runtime assert. It only catches bugs you actually hit during testing.
irql encodes the entire IRQL hierarchy into Rust's type system. Violations become compiler errors:
#[irql(max = Dispatch)]
fn acquire_spinlock() { /* ... */ }
#[irql(max = Passive)]
fn driver_routine() {
call_irql!(acquire_spinlock()); // OK: Passive can raise to Dispatch
}
Wrong transition? Compiler says no:
error[E0277]: IRQL violation: cannot reach `Passive` from `Dispatch`
-- would require lowering
Zero runtime cost, zero binary overhead -- everything is erased during monomorphization.
How it works: #[irql(max = Dispatch)] adds a hidden IRQL type parameter bounded by IrqlCanRaiseTo<Dispatch>. call_irql! threads it through every call as a turbofish argument. The compiler checks the full chain.
Also includes (optional alloc feature, nightly):
IrqlBoxandIrqlVecwith automatic kernel pool selection (PagedPool vs NonPagedPool)- Compile-time drop safety -- paged-pool memory can't be dropped at
Dispatchor above, enforced via auto traits - All allocations are fallible (
Result) -- no OOM panics, no OOM blue screens
Core crate builds on stable. Works on functions, impl blocks, and trait impl blocks.
I wrote a blog post covering the full story and internals: irql: Compile-Time IRQL Safety for Windows Kernel Drivers in Rust
- GitHub: https://github.com/naorhaziz/irql
- Crates.io: https://crates.io/crates/irql
- Docs: https://docs.rs/irql
Would love feedback, especially from anyone doing Rust driver development.