From fa2867d1638c7b0d897955bf96e00bdf1cd0b667 Mon Sep 17 00:00:00 2001 From: Melvin Wang Date: Tue, 4 Feb 2025 16:18:22 -0800 Subject: [PATCH] feat: add support for Storage API subset in `wdk-sys` --- crates/wdk-build/src/lib.rs | 33 +++++++++++++++++++ crates/wdk-sys/Cargo.toml | 1 + crates/wdk-sys/build.rs | 44 ++++++++++++++++++++++++++ crates/wdk-sys/src/lib.rs | 10 ++++++ crates/wdk-sys/src/storage.rs | 36 +++++++++++++++++++++ examples/sample-kmdf-driver/Cargo.toml | 1 + examples/sample-umdf-driver/Cargo.toml | 1 + examples/sample-wdm-driver/Cargo.toml | 2 +- 8 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 crates/wdk-sys/src/storage.rs diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 9494d9d39..13d676192 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -201,6 +201,8 @@ pub enum ApiSubset { Hid, /// API subset for SPB (Serial Peripheral Bus) drivers: Spb, + /// API subset for Storage drivers: + Storage, } impl Default for Config { @@ -684,6 +686,37 @@ impl Config { spb_headers } + ApiSubset::Storage => { + let mut storage_headers = vec![ + "ehstorioctl.h", + "ntddcdrm.h", + "ntddcdvd.h", + "ntdddisk.h", + "ntddmmc.h", + "ntddscsi.h", + "ntddstor.h", + "ntddtape.h", + "ntddvol.h", + "ufs.h", + ]; + + if let DriverConfig::Wdm | DriverConfig::Kmdf(_) = self.driver_config { + storage_headers.extend([ + "mountdev.h", + "mountmgr.h", + "ntddchgr.h", + "ntdddump.h", + "storduid.h", + "storport.h", + ]); + } + + if let DriverConfig::Kmdf(_) = self.driver_config { + storage_headers.extend(["ehstorbandmgmt.h"]); + } + + storage_headers + } } .into_iter() .map(std::string::ToString::to_string) diff --git a/crates/wdk-sys/Cargo.toml b/crates/wdk-sys/Cargo.toml index f7f030b8c..4533fc69a 100644 --- a/crates/wdk-sys/Cargo.toml +++ b/crates/wdk-sys/Cargo.toml @@ -37,6 +37,7 @@ default = [] hid = [] spb = [] +storage = [] nightly = ["wdk-macros/nightly"] test-stubs = [] diff --git a/crates/wdk-sys/build.rs b/crates/wdk-sys/build.rs index 10b66cb47..a886d2df7 100644 --- a/crates/wdk-sys/build.rs +++ b/crates/wdk-sys/build.rs @@ -133,6 +133,7 @@ const BINDGEN_FILE_GENERATORS_TUPLES: &[(&str, GenerateFn)] = &[ ("wdf.rs", generate_wdf), ("hid.rs", generate_hid), ("spb.rs", generate_spb), + ("storage.rs", generate_storage), ]; fn initialize_tracing() -> Result<(), ParseError> { @@ -199,6 +200,8 @@ fn generate_constants(out_path: &Path, config: &Config) -> Result<(), ConfigErro ApiSubset::Hid, #[cfg(feature = "spb")] ApiSubset::Spb, + #[cfg(feature = "storage")] + ApiSubset::Storage, ]); trace!(header_contents = ?header_contents); @@ -223,6 +226,8 @@ fn generate_types(out_path: &Path, config: &Config) -> Result<(), ConfigError> { ApiSubset::Hid, #[cfg(feature = "spb")] ApiSubset::Spb, + #[cfg(feature = "storage")] + ApiSubset::Storage, ]); trace!(header_contents = ?header_contents); @@ -358,6 +363,45 @@ fn generate_spb(out_path: &Path, config: &Config) -> Result<(), ConfigError> { } } +fn generate_storage(out_path: &Path, config: &Config) -> Result<(), ConfigError> { + cfg_if::cfg_if! { + if #[cfg(feature = "storage")] { + info!("Generating bindings to WDK: storage.rs"); + + let header_contents = config.bindgen_header_contents([ + ApiSubset::Base, + ApiSubset::Wdf, + ApiSubset::Storage, + ]); + trace!(header_contents = ?header_contents); + + let bindgen_builder = { + let mut builder = bindgen::Builder::wdk_default(config)? + .with_codegen_config((CodegenConfig::TYPES | CodegenConfig::VARS).complement()) + .header_contents("storage-input.h", &header_contents); + + // Only allowlist files in the storage-specific files to avoid + // duplicate definitions + for header_file in config.headers(ApiSubset::Storage) { + builder = builder.allowlist_file(format!("(?i).*{header_file}.*")); + } + builder + }; + trace!(bindgen_builder = ?bindgen_builder); + + Ok(bindgen_builder + .generate() + .expect("Bindings should succeed to generate") + .write_to_file(out_path.join("storage.rs"))?) + } else { + let _ = (out_path, config); // Silence unused variable warnings when storage feature is not enabled + + info!("Skipping storage.rs generation since storage feature is not enabled"); + Ok(()) + } + } +} + /// Generates a `wdf_function_count.rs` file in `OUT_DIR` which contains the /// definition of the function `get_wdf_function_count()`. This is required to /// be generated here since the size of the table is derived from either a diff --git a/crates/wdk-sys/src/lib.rs b/crates/wdk-sys/src/lib.rs index 130201cd8..4fbb3bb77 100644 --- a/crates/wdk-sys/src/lib.rs +++ b/crates/wdk-sys/src/lib.rs @@ -49,6 +49,16 @@ pub mod hid; ))] pub mod spb; +#[cfg(all( + any( + driver_model__driver_type = "WDM", + driver_model__driver_type = "KMDF", + driver_model__driver_type = "UMDF" + ), + feature = "storage" +))] +pub mod storage; + #[cfg(feature = "test-stubs")] pub mod test_stubs; diff --git a/crates/wdk-sys/src/storage.rs b/crates/wdk-sys/src/storage.rs new file mode 100644 index 000000000..79e5f6047 --- /dev/null +++ b/crates/wdk-sys/src/storage.rs @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation +// License: MIT OR Apache-2.0 + +//! Direct FFI bindings to Storage APIs from the Windows Driver Kit (WDK) +//! +//! This module contains all bindings to functions, constants, methods, +//! constructors and destructors for Storage headers. Types are not included in +//! this module, but are available in the top-level `wdk_sys` module. + +#[allow( + missing_docs, + reason = "most items in the WDK headers have no inline documentation, so bindgen is unable to \ + generate documentation for their bindings" +)] +mod bindings { + #[allow( + clippy::wildcard_imports, + reason = "the underlying c code relies on all type definitions being in scope, which \ + results in the bindgen generated code relying on the generated types being in \ + scope as well" + )] + #[allow( + unused_imports, + reason = "in certain configurations of the WDK (ex. UMDF), there are no functions related \ + to Storage that can be generated by bindgen, so these types are unused" + )] + use crate::types::*; + + include!(concat!(env!("OUT_DIR"), "/storage.rs")); +} +#[allow( + unused_imports, + reason = "in certain configurations of the WDK (ex. UMDF), there are no functions related to \ + Storage that can be generated by bindgen, so the `bindings` module is empty" +)] +pub use bindings::*; diff --git a/examples/sample-kmdf-driver/Cargo.toml b/examples/sample-kmdf-driver/Cargo.toml index cff1287eb..31d25dfa8 100644 --- a/examples/sample-kmdf-driver/Cargo.toml +++ b/examples/sample-kmdf-driver/Cargo.toml @@ -34,6 +34,7 @@ default = [] hid = ["wdk-sys/hid"] spb = ["wdk-sys/spb"] +storage = ["wdk-sys/storage"] nightly = ["wdk/nightly", "wdk-sys/nightly"] diff --git a/examples/sample-umdf-driver/Cargo.toml b/examples/sample-umdf-driver/Cargo.toml index 3ae09d099..58e6ad883 100644 --- a/examples/sample-umdf-driver/Cargo.toml +++ b/examples/sample-umdf-driver/Cargo.toml @@ -32,6 +32,7 @@ default = [] hid = ["wdk-sys/hid"] spb = ["wdk-sys/spb"] +storage = ["wdk-sys/storage"] nightly = ["wdk/nightly", "wdk-sys/nightly"] diff --git a/examples/sample-wdm-driver/Cargo.toml b/examples/sample-wdm-driver/Cargo.toml index 5fd3a5169..461541425 100644 --- a/examples/sample-wdm-driver/Cargo.toml +++ b/examples/sample-wdm-driver/Cargo.toml @@ -27,12 +27,12 @@ wdk = { path = "../../crates/wdk", version = "0.3.0" } wdk-panic = { path = "../../crates/wdk-panic", version = "0.3.0" } wdk-sys = { path = "../../crates/wdk-sys", version = "0.3.0" } - [features] default = [] hid = ["wdk-sys/hid"] spb = ["wdk-sys/spb"] +storage = ["wdk-sys/storage"] nightly = ["wdk/nightly", "wdk-sys/nightly"]