|
| 1 | +# Copilot Instructions |
| 2 | + |
| 3 | +Rust ports of Windows driver samples from the official [Windows Driver Samples](https://github.com/microsoft/Windows-driver-samples), using crates from [windows-drivers-rs](https://github.com/microsoft/windows-drivers-rs). All driver crates target `#![no_std]` and compile as `cdylib` for the Windows kernel. |
| 4 | + |
| 5 | +## Build Commands |
| 6 | + |
| 7 | +Requires EWDK build environment, Clang (LLVM), and `cargo-make`. |
| 8 | + |
| 9 | +```shell |
| 10 | +# Build all workspace members |
| 11 | +cargo build --locked |
| 12 | + |
| 13 | +# Build and package drivers (stamps INF, creates CAT file in Package/) |
| 14 | +cargo make |
| 15 | + |
| 16 | +# Build a specific driver sample |
| 17 | +cargo make --cwd general/echo/kmdf/driver/DriverSync |
| 18 | + |
| 19 | +# Run the echo test app |
| 20 | +cargo run --bin echoapp |
| 21 | +cargo run --bin echoapp -- -Async |
| 22 | +``` |
| 23 | + |
| 24 | +## Lint and Formatting |
| 25 | + |
| 26 | +CI enforces all of these — run before submitting PRs: |
| 27 | + |
| 28 | +```shell |
| 29 | +# Clippy (treats warnings as errors) |
| 30 | +cargo clippy --locked --all-targets -- -D warnings |
| 31 | + |
| 32 | +# Clippy with nightly features |
| 33 | +cargo +nightly clippy --locked --all-targets --features nightly -- -D warnings |
| 34 | + |
| 35 | +# Rust formatting (requires nightly due to unstable rustfmt options) |
| 36 | +cargo +nightly fmt --all -- --check |
| 37 | + |
| 38 | +# TOML formatting |
| 39 | +taplo fmt --check --diff |
| 40 | + |
| 41 | +# Unused dependency detection |
| 42 | +cargo machete |
| 43 | + |
| 44 | +# Security audit |
| 45 | +cargo audit --deny warnings |
| 46 | + |
| 47 | +# Documentation build (warnings are errors via RUSTDOCFLAGS=-D warnings in CI) |
| 48 | +cargo doc --locked |
| 49 | +``` |
| 50 | + |
| 51 | +## Architecture |
| 52 | + |
| 53 | +### Workspace Layout |
| 54 | + |
| 55 | +- **`general/`** — Functional driver samples (e.g., `echo/kmdf/driver/DriverSync` is a KMDF echo driver) |
| 56 | +- **`tools/`** — Diagnostic/verification drivers (e.g., `dv/kmdf/fail_driver_pool_leak` intentionally leaks memory for Driver Verifier testing) |
| 57 | +- **`general/echo/kmdf/exe`** — User-mode test app (`echoapp`) for the echo driver |
| 58 | + |
| 59 | +### Driver Crate Anatomy |
| 60 | + |
| 61 | +Each driver crate follows this file structure: |
| 62 | + |
| 63 | +- **`lib.rs`** — Crate root with `#![no_std]`, clippy lints, module declarations, context structs, `WDF_*_SIZE` constants, and `wdf_declare_context_type!` macro invocations |
| 64 | +- **`driver.rs`** — `DriverEntry` (exported as `#[export_name = "DriverEntry"]`, `extern "system"`) and `EvtDriverDeviceAdd` callback |
| 65 | +- **`device.rs`** — Device creation, PnP/power callbacks |
| 66 | +- **`queue.rs`** — I/O queue initialization and request handling callbacks |
| 67 | +- **`build.rs`** — Calls `wdk_build::configure_wdk_binary_build()` |
| 68 | +- **`*.inx`** — INF template file for driver installation |
| 69 | + |
| 70 | +### Key Crate Dependencies (from windows-drivers-rs) |
| 71 | + |
| 72 | +| Crate | Purpose | |
| 73 | +|-------|---------| |
| 74 | +| `wdk` | Safe Rust wrappers and macros (`println!`, `paged_code!`, `nt_success`, `wdf::Timer`, `wdf::SpinLock`) | |
| 75 | +| `wdk-sys` | Raw FFI bindings to WDK. Use via `call_unsafe_wdf_function_binding!` macro | |
| 76 | +| `wdk-alloc` | `WdkAllocator` — kernel-compatible global allocator | |
| 77 | +| `wdk-panic` | Kernel-compatible panic handler | |
| 78 | +| `wdk-build` | Build-time configuration for driver compilation and `cargo-make` integration | |
| 79 | + |
| 80 | +## Key Conventions |
| 81 | + |
| 82 | +### Driver Entry Points |
| 83 | + |
| 84 | +- `DriverEntry` must use `#[export_name = "DriverEntry"]` and `extern "system"` calling convention |
| 85 | +- Place init code in `#[link_section = "INIT"]`; place pageable code in `#[link_section = "PAGE"]` and invoke `paged_code!()` at function entry |
| 86 | +- WDF callbacks use `extern "C"` calling convention |
| 87 | + |
| 88 | +### WDF Function Calls |
| 89 | + |
| 90 | +All WDF framework function calls go through the `call_unsafe_wdf_function_binding!` macro from `wdk-sys`. These are always `unsafe` blocks: |
| 91 | + |
| 92 | +```rust |
| 93 | +unsafe { |
| 94 | + call_unsafe_wdf_function_binding!( |
| 95 | + WdfDriverCreate, |
| 96 | + driver as PDRIVER_OBJECT, |
| 97 | + registry_path, |
| 98 | + WDF_NO_OBJECT_ATTRIBUTES, |
| 99 | + &raw mut driver_config, |
| 100 | + driver_handle_output, |
| 101 | + ) |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +### WDF Structure Sizes |
| 106 | + |
| 107 | +WDF structs require their `Size` field to be set. Use const-evaluated `WDF_*_SIZE` constants with compile-time truncation assertions: |
| 108 | + |
| 109 | +```rust |
| 110 | +#[allow( |
| 111 | + clippy::cast_possible_truncation, |
| 112 | + reason = "size_of::<WDF_DRIVER_CONFIG>() is known to fit in ULONG due to below const assert" |
| 113 | +)] |
| 114 | +const WDF_DRIVER_CONFIG_SIZE: ULONG = { |
| 115 | + const S: usize = core::mem::size_of::<WDF_DRIVER_CONFIG>(); |
| 116 | + const { assert!(S <= ULONG::MAX as usize) }; |
| 117 | + S as ULONG |
| 118 | +}; |
| 119 | +``` |
| 120 | + |
| 121 | +### WDF Object Contexts |
| 122 | + |
| 123 | +Context types are registered using macros from `wdf_object_context.rs`: |
| 124 | + |
| 125 | +- `wdf_declare_context_type!(MyContext)` — generates `wdf_object_get_my_context` accessor |
| 126 | +- `wdf_declare_context_type_with_name!(MyContext, custom_getter_name)` — generates a named accessor |
| 127 | +- `wdf_get_context_type_info!(MyContext)` — retrieves the type info pointer for `WDF_OBJECT_ATTRIBUTES.ContextTypeInfo` |
| 128 | + |
| 129 | +### Kernel Allocator and Panic Handler |
| 130 | + |
| 131 | +Every driver crate must include both, gated behind `#[cfg(not(test))]`: |
| 132 | + |
| 133 | +```rust |
| 134 | +#[cfg(not(test))] |
| 135 | +extern crate wdk_panic; |
| 136 | + |
| 137 | +#[cfg(not(test))] |
| 138 | +use wdk_alloc::WdkAllocator; |
| 139 | + |
| 140 | +#[cfg(not(test))] |
| 141 | +#[global_allocator] |
| 142 | +static GLOBAL_ALLOCATOR: WdkAllocator = WdkAllocator; |
| 143 | +``` |
| 144 | + |
| 145 | +### Clippy Configuration |
| 146 | + |
| 147 | +All driver crates enable strict clippy lints: |
| 148 | + |
| 149 | +```rust |
| 150 | +#![deny(clippy::all)] |
| 151 | +#![warn(clippy::pedantic)] |
| 152 | +#![warn(clippy::nursery)] |
| 153 | +#![warn(clippy::cargo)] |
| 154 | +#![allow(clippy::missing_safety_doc)] |
| 155 | +``` |
| 156 | + |
| 157 | +### Nightly Feature Gating |
| 158 | + |
| 159 | +Crates expose an optional `nightly` feature for unstable Rust capabilities. The feature cascades through `wdk` and `wdk-sys`: |
| 160 | + |
| 161 | +```toml |
| 162 | +[features] |
| 163 | +nightly = ["wdk/nightly", "wdk-sys/nightly"] |
| 164 | +``` |
| 165 | + |
| 166 | +### Formatting |
| 167 | + |
| 168 | +- Rust: Uses nightly `rustfmt` with unstable options (see `rustfmt.toml`): `imports_granularity = "Crate"`, `group_imports = "StdExternalCrate"`, `hex_literal_case = "Upper"`, among others |
| 169 | +- TOML: Uses `taplo` with CRLF line endings (`taplo.toml`) |
| 170 | + |
| 171 | +### Rust Flags |
| 172 | + |
| 173 | +`-C target-feature=+crt-static` is set in `.cargo/config.toml` and must also be in CI `RUSTFLAGS`. CI also sets `-D warnings` to deny all warnings. |
| 174 | + |
| 175 | +### Copyright Headers |
| 176 | + |
| 177 | +Every `.rs` file starts with: |
| 178 | + |
| 179 | +```rust |
| 180 | +// Copyright (c) Microsoft Corporation. |
| 181 | +// License: MIT OR Apache-2.0 |
| 182 | +``` |
0 commit comments