diff --git a/README.md b/README.md index 7408fbb0..b2f434f1 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ This repo is a collection of Rust crates that enable developers to develop Windows Drivers in Rust. It is the intention to support both WDM and WDF driver development models. This repo contains the following crates: -* [wdk-build](./crates/wdk-build): A library to configure a Cargo build script for binding generation and downstream linking of the WDK (Windows Developer Kit). While this crate is written to be flexible with different WDK releases and different WDF version, it is currently only tested for NI eWDK, KMDF 1.33, UMDF 2.33, and WDM Drivers. There may be missing linker options for older DDKs. +* [wdk-build](./crates/wdk-build): A library to configure a Cargo build script for binding generation and downstream linking of the WDK (Windows Driver Kit). While this crate is written to be flexible with different WDK releases and different WDF version, it is currently only tested for NI eWDK, KMDF 1.33, UMDF 2.33, and WDM Drivers. There may be missing linker options for older DDKs. * [wdk-sys](./crates/wdk-sys): Direct FFI bindings to APIs available in the Windows Development Kit (WDK). This includes both autogenerated ffi bindings from `bindgen`, and also manual re-implementations of macros that bindgen fails to generate. * [wdk](./crates/wdk): Safe idiomatic bindings to APIs available in the Windows Development Kit (WDK) * [wdk-panic](./crates/wdk-panic/): Default panic handler implementations for programs built with WDK diff --git a/crates/sample-kmdf-driver/src/lib.rs b/crates/sample-kmdf-driver/src/lib.rs index 6ed35f0f..255352b8 100644 --- a/crates/sample-kmdf-driver/src/lib.rs +++ b/crates/sample-kmdf-driver/src/lib.rs @@ -8,6 +8,7 @@ #![deny(clippy::pedantic)] #![deny(clippy::nursery)] #![deny(clippy::cargo)] +#![deny(clippy::unnecessary_safety_doc)] extern crate alloc; diff --git a/crates/wdk-alloc/src/lib.rs b/crates/wdk-alloc/src/lib.rs index b669d15c..6b8f930c 100644 --- a/crates/wdk-alloc/src/lib.rs +++ b/crates/wdk-alloc/src/lib.rs @@ -1,12 +1,37 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +//! Allocator implementation to use with `#[global_allocator]` to allow use of +//! [`core::alloc`]. +//! +//! # Example +//! ```rust, no_run +//! #[cfg(not(test))] +//! use wdk_alloc::WDKAllocator; +//! +//! #[cfg(not(test))] +//! #[global_allocator] +//! static GLOBAL_ALLOCATOR: WDKAllocator = WDKAllocator; +//! ``` + #![no_std] #![deny(warnings)] +#![deny(missing_docs)] #![deny(clippy::all)] #![deny(clippy::pedantic)] #![deny(clippy::nursery)] #![deny(clippy::cargo)] +#![deny(clippy::undocumented_unsafe_blocks)] +#![deny(clippy::unnecessary_safety_doc)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] +#![deny(rustdoc::missing_crate_level_docs)] +#![deny(rustdoc::invalid_codeblock_attributes)] +#![deny(rustdoc::invalid_html_tags)] +#![deny(rustdoc::invalid_rust_codeblocks)] +#![deny(rustdoc::bare_urls)] +#![deny(rustdoc::unescaped_backticks)] +#![deny(rustdoc::redundant_explicit_links)] use core::alloc::{GlobalAlloc, Layout}; @@ -17,6 +42,9 @@ use wdk_sys::{ SIZE_T, ULONG, }; + +/// Allocator implementation to use with `#[global_allocator]` to allow use of +/// [`core::alloc`]. pub struct WDKAllocator; // The value of memory tags are stored in little-endian order, so it is @@ -32,10 +60,17 @@ lazy_static! { ); } +// SAFETY: This is safe because the WDK allocator: +// 1. can never unwind since it can never panic +// 2. has implementations of alloc and dealloc that maintain layout +// constraints (FIXME: Alignment of the layout is currenty not +// supported) unsafe impl GlobalAlloc for WDKAllocator { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { let ptr = ExAllocatePool2(POOL_FLAG_NON_PAGED, layout.size() as SIZE_T, *RUST_TAG); - assert!(!ptr.is_null(), "wdk-alloc failed to allocate memory."); + if ptr.is_null() { + return core::ptr::null_mut(); + } ptr.cast() } diff --git a/crates/wdk-build/Cargo.toml b/crates/wdk-build/Cargo.toml index aa949ac9..ed2dbedc 100644 --- a/crates/wdk-build/Cargo.toml +++ b/crates/wdk-build/Cargo.toml @@ -2,7 +2,7 @@ edition.workspace = true name = "wdk-build" version = "0.1.0" -description = "A library to configure a Cargo build script for binding generation and downstream linking of the WDK (Windows Developer Kit)" +description = "A library to configure a Cargo build script for binding generation and downstream linking of the WDK (Windows Driver Kit)" repository.workspace = true readme.workspace = true license.workspace = true diff --git a/crates/wdk-build/src/bindgen.rs b/crates/wdk-build/src/bindgen.rs index 6b5d9073..7c7cf8b8 100644 --- a/crates/wdk-build/src/bindgen.rs +++ b/crates/wdk-build/src/bindgen.rs @@ -4,6 +4,9 @@ use bindgen::Builder; use crate::{CPUArchitecture, Config, ConfigError, DriverConfig}; + +/// An extension trait that provides a way to create a [`bindgen::Builder`] +/// configured for generating bindings to the wdk pub trait BuilderExt { /// Returns a `bindgen::Builder` with the default configuration for /// generation of bindings to the WDK @@ -59,13 +62,13 @@ impl BuilderExt for Builder { DriverConfig::WDM() => { vec![] } - DriverConfig::KMDFConfig(kmdf_config) => { + DriverConfig::KMDF(kmdf_config) => { vec![ format!("KMDF_VERSION_MAJOR={}", kmdf_config.kmdf_version_major), format!("KMDF_VERSION_MINOR={}", kmdf_config.kmdf_version_minor), ] } - DriverConfig::UMDFConfig(umdf_config) => { + DriverConfig::UMDF(umdf_config) => { let mut umdf_definitions = vec![ format!("UMDF_VERSION_MAJOR={}", umdf_config.umdf_version_major), format!("UMDF_VERSION_MINOR={}", umdf_config.umdf_version_minor), diff --git a/crates/wdk-build/src/lib.rs b/crates/wdk-build/src/lib.rs index 519bfbe4..0a5fabe2 100644 --- a/crates/wdk-build/src/lib.rs +++ b/crates/wdk-build/src/lib.rs @@ -1,12 +1,32 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +//! [`wdk-build`] is a library that is used within Cargo build scripts to +//! configure any build that depends on the WDK (Windows Driver Kit). This is +//! especially useful for crates that generate FFI bindings to the WDK, +//! WDK-dependent libraries, and programs built on top of the WDK (ex. Drivers). +//! This library is built to be able to accomodate different WDK releases, as +//! well strives to allow for all the configuration the WDK allows. This +//! includes being ables to select different WDF versions and different driver +//! models (WDM, KMDF, UMDF). #![cfg_attr(nightly_toolchain, feature(assert_matches))] #![deny(warnings)] +#![deny(missing_docs)] #![deny(clippy::all)] #![deny(clippy::pedantic)] #![deny(clippy::nursery)] #![deny(clippy::cargo)] +#![deny(clippy::undocumented_unsafe_blocks)] +#![deny(clippy::unnecessary_safety_doc)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] +#![deny(rustdoc::missing_crate_level_docs)] +#![deny(rustdoc::invalid_codeblock_attributes)] +#![deny(rustdoc::invalid_html_tags)] +#![deny(rustdoc::invalid_rust_codeblocks)] +#![deny(rustdoc::bare_urls)] +#![deny(rustdoc::unescaped_backticks)] +#![deny(rustdoc::redundant_explicit_links)] mod bindgen; mod utils; @@ -18,88 +38,144 @@ use serde::{Deserialize, Serialize}; use thiserror::Error; use utils::PathExt; +/// Configuration parameters for a build dependent on the WDK #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub struct Config { + /// Path to root of WDK. Corresponds with WDKContentRoot environment + /// varialbe in eWDK pub wdk_content_root: PathBuf, + /// Build configuration of driver pub driver_config: DriverConfig, + /// CPU architecture to target pub cpu_architecture: CPUArchitecture, } +/// The driver type with its associated configuration parameters #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] pub enum DriverConfig { + /// Windows Driver Model WDM(), - KMDFConfig(KMDFConfig), - UMDFConfig(UMDFConfig), + /// Kernel Mode Driver Framework + KMDF(KMDFConfig), + /// User Mode Driver Framework + UMDF(UMDFConfig), } +/// Driver model type #[derive(Debug, Clone, Copy)] pub enum DriverType { /// Windows Driver Model WDM, /// Kernel Mode Driver Framework - KMDFConfig, + KMDF, /// User Mode Driver Framework - UMDFConfig, + UMDF, } +/// The CPU architecture that's configured to be compiled for #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub enum CPUArchitecture { + /// AMD64 CPU architecture. Also known as x64 or x86-64. AMD64, + /// ARM64 CPU architecture. Also known as aarch64. ARM64, } + +/// The configuration parameters for KMDF drivers #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub struct KMDFConfig { + /// Major KMDF Version pub kmdf_version_major: u8, + /// Minor KMDF Version pub kmdf_version_minor: u8, } +/// The configuration parameters for UMDF drivers #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub struct UMDFConfig { + /// Major UMDF Version pub umdf_version_major: u8, + /// Minor UMDF Version pub umdf_version_minor: u8, } +/// Errors that could result from configuring a build via [`wdk-build`] #[derive(Debug, Error)] pub enum ConfigError { + /// Error returned when an std::io operation fails #[error(transparent)] IoError(#[from] std::io::Error), + + /// Error returned when an expected directory does not exist #[error("cannot find directory: {directory}")] - DirectoryNotFound { directory: String }, + DirectoryNotFound { + /// Path of directory that was not found + directory: String, + }, + + /// Error returned when an + /// `utils::PathExt::strip_extended_length_path_prefix` operation fails #[error(transparent)] StripExtendedPathPrefixError(#[from] utils::StripExtendedPathPrefixError), + + /// Error returned when a [`Config`] fails to be parsed from the environment #[error(transparent)] ConfigFromEnvError(#[from] ConfigFromEnvError), + + /// Error returned when a [`Config`] fails to be exported to the environment #[error(transparent)] ExportError(#[from] ExportError), } +/// Errors that could result from parsing a configuration from a [`wdk-build`] +/// build environment #[derive(Debug, Error)] pub enum ConfigFromEnvError { + /// Error returned when an expected environment variable is not found #[error(transparent)] EnvError(#[from] std::env::VarError), + + /// Error returned when [`serde_json`] fails to deserialize the [`Config`] #[error(transparent)] DeserializeError(#[from] serde_json::Error), + + /// Error returned when the config from one WDK dependency does not match + /// the config from another #[error( "config from {config_1_source} does not match config from {config_2_source}:\nconfig_1: \ {config_1:?}\nconfig_2: {config_2:?}" )] ConfigMismatch { + /// Config from the first dependency config_1: Box, + /// DEP_ environment variable name indicating the source of the first + /// dependency config_1_source: String, + /// Config from the second dependency config_2: Box, + /// DEP_ environment variable name indicating the source of the second + /// dependency config_2_source: String, }, + + /// Error returned when no WDK configs exported from dependencies could be + /// found #[error("no WDK configs exported from dependencies could be found")] ConfigNotFound, } +/// Errors that could result from exporting a [`wdk-build`] build configuration #[derive(Debug, Error)] pub enum ExportError { + /// Error returned when the crate being compiled does not have a `links` + /// value in its Cargo.toml #[error( "Missing `links` value in crate's config.toml. Metadata is unable to propogate to \ dependencies without a `links` value" )] MissingLinksValue(#[from] std::env::VarError), + + /// Error returned when [`serde_json`] fails to serialize the [`Config`] #[error(transparent)] SerializeError(#[from] serde_json::Error), } @@ -121,6 +197,7 @@ impl Default for Config { impl Config { const CARGO_CONFIG_KEY: &'static str = "wdk_config"; + /// Creates a new [`Config`] with default values #[must_use] pub fn new() -> Self { Self::default() @@ -232,8 +309,8 @@ impl Config { ); let km_or_um_include_path = windows_sdk_include_path.join(match self.driver_config { - DriverConfig::WDM() | DriverConfig::KMDFConfig(_) => "km", - DriverConfig::UMDFConfig(_) => "um", + DriverConfig::WDM() | DriverConfig::KMDF(_) => "km", + DriverConfig::UMDF(_) => "um", }); if !km_or_um_include_path.is_dir() { return Err(ConfigError::DirectoryNotFound { @@ -261,10 +338,10 @@ impl Config { // Add other driver type-specific include paths match &self.driver_config { DriverConfig::WDM() => {} - DriverConfig::KMDFConfig(kmdf_options) => { + DriverConfig::KMDF(kmdf_config) => { let kmdf_include_path = include_directory.join(format!( "wdf/kmdf/{}.{}", - kmdf_options.kmdf_version_major, kmdf_options.kmdf_version_minor + kmdf_config.kmdf_version_major, kmdf_config.kmdf_version_minor )); if !kmdf_include_path.is_dir() { return Err(ConfigError::DirectoryNotFound { @@ -277,10 +354,10 @@ impl Config { .strip_extended_length_path_prefix()?, ); } - DriverConfig::UMDFConfig(umdf_options) => { + DriverConfig::UMDF(umdf_config) => { let umdf_include_path = include_directory.join(format!( "wdf/umdf/{}.{}", - umdf_options.umdf_version_major, umdf_options.umdf_version_minor + umdf_config.umdf_version_major, umdf_config.umdf_version_minor )); if !umdf_include_path.is_dir() { return Err(ConfigError::DirectoryNotFound { @@ -318,10 +395,10 @@ impl Config { library_directory .join(sdk_version) .join(match self.driver_config { - DriverConfig::WDM() | DriverConfig::KMDFConfig(_) => { + DriverConfig::WDM() | DriverConfig::KMDF(_) => { format!("km/{}", self.cpu_architecture.to_windows_str(),) } - DriverConfig::UMDFConfig(_) => { + DriverConfig::UMDF(_) => { format!("um/{}", self.cpu_architecture.to_windows_str(),) } }); @@ -339,12 +416,12 @@ impl Config { // Add other driver type-specific library paths match &self.driver_config { DriverConfig::WDM() => (), - DriverConfig::KMDFConfig(kmdf_options) => { + DriverConfig::KMDF(kmdf_config) => { let kmdf_library_path = library_directory.join(format!( "wdf/kmdf/{}/{}.{}", self.cpu_architecture.to_windows_str(), - kmdf_options.kmdf_version_major, - kmdf_options.kmdf_version_minor + kmdf_config.kmdf_version_major, + kmdf_config.kmdf_version_minor )); if !kmdf_library_path.is_dir() { return Err(ConfigError::DirectoryNotFound { @@ -357,12 +434,12 @@ impl Config { .strip_extended_length_path_prefix()?, ); } - DriverConfig::UMDFConfig(umdf_options) => { + DriverConfig::UMDF(umdf_config) => { let umdf_library_path = library_directory.join(format!( "wdf/umdf/{}/{}.{}", self.cpu_architecture.to_windows_str(), - umdf_options.umdf_version_major, - umdf_options.umdf_version_minor + umdf_config.umdf_version_major, + umdf_config.umdf_version_minor )); if !umdf_library_path.is_dir() { return Err(ConfigError::DirectoryNotFound { @@ -412,8 +489,8 @@ impl Config { println!("cargo:rustc-link-lib=hal"); println!("cargo:rustc-link-lib=wmilib"); } - DriverConfig::KMDFConfig(_) => { - // Emit KMDFConfig-specific libraries to link to + DriverConfig::KMDF(_) => { + // Emit KMDF-specific libraries to link to println!("cargo:rustc-link-lib=BufferOverflowFastFailK"); println!("cargo:rustc-link-lib=ntoskrnl"); println!("cargo:rustc-link-lib=hal"); @@ -421,8 +498,8 @@ impl Config { println!("cargo:rustc-link-lib=WdfLdr"); println!("cargo:rustc-link-lib=WdfDriverEntry"); } - DriverConfig::UMDFConfig(umdf_options) => { - // Emit UMDFConfig-specific libraries to link to + DriverConfig::UMDF(umdf_config) => { + // Emit UMDF-specific libraries to link to match env::var("PROFILE") .expect( "Cargo should have set a valid PROFILE environment variable at build time", @@ -440,7 +517,7 @@ impl Config { } } - if umdf_options.umdf_version_major >= 2 { + if umdf_config.umdf_version_major >= 2 { println!("cargo:rustc-link-lib=WdfDriverStubUm"); println!("cargo:rustc-link-lib=ntdll"); } @@ -488,18 +565,18 @@ impl Config { // WDK println!("cargo:rustc-cdylib-link-arg=/ENTRY:DriverEntry"); } - DriverConfig::KMDFConfig(_) => { + DriverConfig::KMDF(_) => { // Linker arguments derived from WindowsDriver.KernelMode.props in Ni(22H2) WDK println!("cargo:rustc-cdylib-link-arg=/DRIVER"); println!("cargo:rustc-cdylib-link-arg=/NODEFAULTLIB"); println!("cargo:rustc-cdylib-link-arg=/SUBSYSTEM:NATIVE"); println!("cargo:rustc-cdylib-link-arg=/KERNEL"); - // Linker arguments derived from WindowsDriver.KernelMode.KMDFConfig.props in + // Linker arguments derived from WindowsDriver.KernelMode.KMDF.props in // Ni(22H2) WDK println!("cargo:rustc-cdylib-link-arg=/ENTRY:FxDriverEntry"); } - DriverConfig::UMDFConfig(_) => { + DriverConfig::UMDF(_) => { // Linker arguments derived from WindowsDriver.UserMode.props in Ni(22H2) WDK println!("cargo:rustc-cdylib-link-arg=/SUBSYSTEM:WINDOWS"); } @@ -542,6 +619,7 @@ impl Default for KMDFConfig { } impl KMDFConfig { + /// Creates a new [`KMDFConfig`] with default values #[must_use] pub fn new() -> Self { Self::default() @@ -560,6 +638,7 @@ impl Default for UMDFConfig { } impl UMDFConfig { + /// Creates a new [`UMDFConfig`] with default values #[must_use] pub fn new() -> Self { Self::default() @@ -567,6 +646,8 @@ impl UMDFConfig { } impl CPUArchitecture { + /// Converts [`CPUArchitecture`] to the string corresponding to what the + /// architecture is typically referred to in Windows #[must_use] pub const fn to_windows_str(&self) -> &str { match self { @@ -639,48 +720,48 @@ mod tests { } #[test] - fn default_options() { - let wdk_build_options = with_env(&[("CARGO_CFG_TARGET_ARCH", "x86_64")], Config::new); + fn default_config() { + let config = with_env(&[("CARGO_CFG_TARGET_ARCH", "x86_64")], Config::new); #[cfg(nightly_toolchain)] - assert_matches!(wdk_build_options.driver_config, DriverConfig::WDM()); - assert_eq!(wdk_build_options.cpu_architecture, CPUArchitecture::AMD64); + assert_matches!(config.driver_config, DriverConfig::WDM()); + assert_eq!(config.cpu_architecture, CPUArchitecture::AMD64); } #[test] - fn wdm_options() { - let wdk_build_options = with_env(&[("CARGO_CFG_TARGET_ARCH", "x86_64")], || Config { + fn wdm_config() { + let config = with_env(&[("CARGO_CFG_TARGET_ARCH", "x86_64")], || Config { driver_config: DriverConfig::WDM(), ..Config::default() }); #[cfg(nightly_toolchain)] - assert_matches!(wdk_build_options.driver_config, DriverConfig::WDM()); - assert_eq!(wdk_build_options.cpu_architecture, CPUArchitecture::AMD64); + assert_matches!(config.driver_config, DriverConfig::WDM()); + assert_eq!(config.cpu_architecture, CPUArchitecture::AMD64); } #[test] - fn default_kmdf_options() { - let wdk_build_options = with_env(&[("CARGO_CFG_TARGET_ARCH", "x86_64")], || Config { - driver_config: DriverConfig::KMDFConfig(KMDFConfig::new()), + fn default_kmdf_config() { + let config = with_env(&[("CARGO_CFG_TARGET_ARCH", "x86_64")], || Config { + driver_config: DriverConfig::KMDF(KMDFConfig::new()), ..Config::default() }); #[cfg(nightly_toolchain)] assert_matches!( - wdk_build_options.driver_config, - DriverConfig::KMDFConfig(KMDFConfig { + config.driver_config, + DriverConfig::KMDF(KMDFConfig { kmdf_version_major: 1, kmdf_version_minor: 33 }) ); - assert_eq!(wdk_build_options.cpu_architecture, CPUArchitecture::AMD64); + assert_eq!(config.cpu_architecture, CPUArchitecture::AMD64); } #[test] - fn kmdf_options() { - let wdk_build_options = with_env(&[("CARGO_CFG_TARGET_ARCH", "x86_64")], || Config { - driver_config: DriverConfig::KMDFConfig(KMDFConfig { + fn kmdf_config() { + let config = with_env(&[("CARGO_CFG_TARGET_ARCH", "x86_64")], || Config { + driver_config: DriverConfig::KMDF(KMDFConfig { kmdf_version_major: 1, kmdf_version_minor: 15, }), @@ -689,37 +770,37 @@ mod tests { #[cfg(nightly_toolchain)] assert_matches!( - wdk_build_options.driver_config, - DriverConfig::KMDFConfig(KMDFConfig { + config.driver_config, + DriverConfig::KMDF(KMDFConfig { kmdf_version_major: 1, kmdf_version_minor: 15 }) ); - assert_eq!(wdk_build_options.cpu_architecture, CPUArchitecture::AMD64); + assert_eq!(config.cpu_architecture, CPUArchitecture::AMD64); } #[test] - fn default_umdf_options() { - let wdk_build_options = with_env(&[("CARGO_CFG_TARGET_ARCH", "x86_64")], || Config { - driver_config: DriverConfig::UMDFConfig(UMDFConfig::new()), + fn default_umdf_config() { + let config = with_env(&[("CARGO_CFG_TARGET_ARCH", "x86_64")], || Config { + driver_config: DriverConfig::UMDF(UMDFConfig::new()), ..Config::default() }); #[cfg(nightly_toolchain)] assert_matches!( - wdk_build_options.driver_config, - DriverConfig::UMDFConfig(UMDFConfig { + config.driver_config, + DriverConfig::UMDF(UMDFConfig { umdf_version_major: 2, umdf_version_minor: 33 }) ); - assert_eq!(wdk_build_options.cpu_architecture, CPUArchitecture::AMD64); + assert_eq!(config.cpu_architecture, CPUArchitecture::AMD64); } #[test] - fn umdf_options() { - let wdk_build_options = with_env(&[("CARGO_CFG_TARGET_ARCH", "aarch64")], || Config { - driver_config: DriverConfig::UMDFConfig(UMDFConfig { + fn umdf_config() { + let config = with_env(&[("CARGO_CFG_TARGET_ARCH", "aarch64")], || Config { + driver_config: DriverConfig::UMDF(UMDFConfig { umdf_version_major: 2, umdf_version_minor: 15, }), @@ -728,12 +809,12 @@ mod tests { #[cfg(nightly_toolchain)] assert_matches!( - wdk_build_options.driver_config, - DriverConfig::UMDFConfig(UMDFConfig { + config.driver_config, + DriverConfig::UMDF(UMDFConfig { umdf_version_major: 2, umdf_version_minor: 15 }) ); - assert_eq!(wdk_build_options.cpu_architecture, CPUArchitecture::ARM64); + assert_eq!(config.cpu_architecture, CPUArchitecture::ARM64); } } diff --git a/crates/wdk-build/src/utils.rs b/crates/wdk-build/src/utils.rs index e3c24a8e..b9e76ba1 100644 --- a/crates/wdk-build/src/utils.rs +++ b/crates/wdk-build/src/utils.rs @@ -23,6 +23,7 @@ use windows::{ use crate::{CPUArchitecture, ConfigError}; +/// Errors that may occur when stripping the extended path prefix from a path #[derive(Debug, Error, PartialEq, Eq)] pub enum StripExtendedPathPrefixError { #[error("provided path is empty")] @@ -169,6 +170,7 @@ fn read_registry_key_string_value( ) -> Option { let mut opened_key_handle = HKEY::default(); let mut len = 0; + // SAFETY: FIXME seperate unsafe blocks unsafe { if RegOpenKeyExA(key_handle, sub_key, 0, KEY_READ, &mut opened_key_handle).is_ok() { if RegGetValueA( @@ -302,6 +304,7 @@ mod tests { #[test] fn read_reg_key_programfilesdir() { let program_files_dir = + // SAFETY: FOLDERID_ProgramFiles is a constant from the windows crate, so dereference a pointer re-borrowed from its reference is always valid unsafe { SHGetKnownFolderPath(&FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, None) } .expect("Program Files Folder should always resolve via SHGetKnownFolderPath."); @@ -312,6 +315,8 @@ mod tests { s!("ProgramFilesDir") ), Some( + // SAFETY: program_files_dir pointer stays valid for reads up until and including + // its terminating null unsafe { program_files_dir.to_string() } .expect("Path resolved from FOLDERID_ProgramFiles should be valid UTF16.") ) diff --git a/crates/wdk-macros/src/lib.rs b/crates/wdk-macros/src/lib.rs index cf455be2..11cfcfe1 100644 --- a/crates/wdk-macros/src/lib.rs +++ b/crates/wdk-macros/src/lib.rs @@ -1,12 +1,26 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +//! A collection of macros that help make it easier to interact with +//! [`wdk-sys`]'s direct bindings to the Windows Driver Kit (WDK). #![cfg_attr(feature = "nightly", feature(hint_must_use))] #![deny(warnings)] +#![deny(missing_docs)] #![deny(clippy::all)] #![deny(clippy::pedantic)] #![deny(clippy::nursery)] #![deny(clippy::cargo)] +#![deny(clippy::undocumented_unsafe_blocks)] +#![deny(clippy::unnecessary_safety_doc)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] +#![deny(rustdoc::missing_crate_level_docs)] +#![deny(rustdoc::invalid_codeblock_attributes)] +#![deny(rustdoc::invalid_html_tags)] +#![deny(rustdoc::invalid_rust_codeblocks)] +#![deny(rustdoc::bare_urls)] +#![deny(rustdoc::unescaped_backticks)] +#![deny(rustdoc::redundant_explicit_links)] use cfg_if::cfg_if; use proc_macro::TokenStream; @@ -21,6 +35,41 @@ use syn::{ Token, }; +/// A procedural macro that allows WDF functions to be called by name. +/// +/// This function parses the name of the WDF function, finds it function pointer +/// from the WDF function table, and then calls it with the arguments passed to +/// it +/// +/// # Examples +/// +/// ```rust, no_run +/// #![cfg_attr(feature = "nightly", feature(hint_must_use))] +/// use wdk_sys::*; +/// +/// #[export_name = "DriverEntry"] +/// pub extern "system" fn driver_entry( +/// driver: &mut DRIVER_OBJECT, +/// registry_path: PCUNICODE_STRING, +/// ) -> NTSTATUS { +/// let mut driver_config = WDF_DRIVER_CONFIG { +/// Size: core::mem::size_of::() as ULONG, +/// ..WDF_DRIVER_CONFIG::default() +/// }; +/// let driver_handle_output = WDF_NO_HANDLE as *mut WDFDRIVER; +/// +/// unsafe { +/// wdk_macros::call_unsafe_wdf_function_binding!( +/// WdfDriverCreate, +/// driver as PDRIVER_OBJECT, +/// registry_path, +/// WDF_NO_OBJECT_ATTRIBUTES, +/// &mut driver_config, +/// driver_handle_output, +/// ) +/// } +/// } +/// ``` #[proc_macro] pub fn call_unsafe_wdf_function_binding(input_tokens: TokenStream) -> TokenStream { call_unsafe_wdf_function_binding_impl(TokenStream2::from(input_tokens)).into() @@ -148,7 +197,7 @@ mod tests { /// `TestCases::pass`. `cargo build` will fail at link stage due to /// `trybuild` not allowing configuration to compile as a`cdylib`. To /// work around this, `compile_fail` is used, and we mark the test as - /// expecting to pnaic with a specific message using the `should_panic` + /// expecting to panic with a specific message using the `should_panic` /// attribute macro. macro_rules! generate_macro_expansion_and_compilation_tests { ($($filename:ident),+) => { @@ -288,7 +337,7 @@ mod tests { #[test] fn trybuild() { trybuild::TestCases::new().compile_fail( - // canonicalizing this path causes a bug in `glob`: https://github.com/rust-lang/glob/issues/132 + // canonicalization of this path causes a bug in `glob`: https://github.com/rust-lang/glob/issues/132 TRYBUILD_FOLDER_PATH // .canonicalize()? .join("*.rs"), ); diff --git a/crates/wdk-panic/src/lib.rs b/crates/wdk-panic/src/lib.rs index ab45f6c6..c0e81179 100644 --- a/crates/wdk-panic/src/lib.rs +++ b/crates/wdk-panic/src/lib.rs @@ -1,12 +1,25 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +//! Default Panic Handlers for programs built with the WDK (Windows Drivers Kit) #![no_std] #![deny(warnings)] +#![deny(missing_docs)] #![deny(clippy::all)] -#![warn(clippy::pedantic)] -#![warn(clippy::nursery)] -#![warn(clippy::cargo)] +#![deny(clippy::pedantic)] +#![deny(clippy::nursery)] +#![deny(clippy::cargo)] +#![deny(clippy::undocumented_unsafe_blocks)] +#![deny(clippy::unnecessary_safety_doc)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] +#![deny(rustdoc::missing_crate_level_docs)] +#![deny(rustdoc::invalid_codeblock_attributes)] +#![deny(rustdoc::invalid_html_tags)] +#![deny(rustdoc::invalid_rust_codeblocks)] +#![deny(rustdoc::bare_urls)] +#![deny(rustdoc::unescaped_backticks)] +#![deny(rustdoc::redundant_explicit_links)] #[cfg(not(test))] use core::panic::PanicInfo; diff --git a/crates/wdk-sys/build.rs b/crates/wdk-sys/build.rs index a3c250ed..97b3a4aa 100644 --- a/crates/wdk-sys/build.rs +++ b/crates/wdk-sys/build.rs @@ -69,7 +69,7 @@ fn main() -> Result<(), ConfigError> { let config = Config { // FIXME: this should be based off of Cargo feature version - driver_config: DriverConfig::KMDFConfig(KMDFConfig::new()), + driver_config: DriverConfig::KMDF(KMDFConfig::new()), ..Config::default() }; diff --git a/crates/wdk-sys/generated_bindings/constants.rs b/crates/wdk-sys/generated_bindings/constants.rs index 5d0ed54a..beffc822 100644 --- a/crates/wdk-sys/generated_bindings/constants.rs +++ b/crates/wdk-sys/generated_bindings/constants.rs @@ -1958,7 +1958,6 @@ pub const PF_AVX512F_INSTRUCTIONS_AVAILABLE: u32 = 41; pub const PF_ERMS_AVAILABLE: u32 = 42; pub const PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE: u32 = 43; pub const PF_ARM_V83_JSCVT_INSTRUCTIONS_AVAILABLE: u32 = 44; -pub const PF_ARM_V83_LRCPC_INSTRUCTIONS_AVAILABLE: u32 = 45; pub const IsNEC_98: u32 = 0; pub const IsNotNEC_98: u32 = 1; pub const PROCESSOR_FEATURE_MAX: u32 = 64; @@ -2458,9 +2457,8 @@ pub const DMA_IOMMU_INTERFACE_VERSION: u32 = 1; pub const DMA_IOMMU_INTERFACE_EX_VERSION_1: u32 = 1; pub const DMA_IOMMU_INTERFACE_EX_VERSION_2: u32 = 2; pub const DMA_IOMMU_INTERFACE_EX_VERSION_MIN: u32 = 1; -pub const DMA_IOMMU_INTERFACE_EX_VERSION_3: u32 = 3; -pub const DMA_IOMMU_INTERFACE_EX_VERSION_MAX: u32 = 3; -pub const DMA_IOMMU_INTERFACE_EX_VERSION: u32 = 3; +pub const DMA_IOMMU_INTERFACE_EX_VERSION_MAX: u32 = 2; +pub const DMA_IOMMU_INTERFACE_EX_VERSION: u32 = 1; pub const PO_MEM_PRESERVE: u32 = 1; pub const PO_MEM_CLONE: u32 = 2; pub const PO_MEM_CL_OR_NCHK: u32 = 4; @@ -3687,7 +3685,6 @@ pub const TOKEN_READ: u32 = 131080; pub const TOKEN_WRITE: u32 = 131296; pub const TOKEN_EXECUTE: u32 = 131072; pub const TOKEN_TRUST_CONSTRAINT_MASK: u32 = 131096; -pub const TOKEN_TRUST_ALLOWED_MASK: u32 = 131102; pub const TOKEN_ACCESS_PSEUDO_HANDLE_WIN8: u32 = 24; pub const TOKEN_ACCESS_PSEUDO_HANDLE: u32 = 24; pub const TOKEN_MANDATORY_POLICY_OFF: u32 = 0; diff --git a/crates/wdk-sys/generated_bindings/types.rs b/crates/wdk-sys/generated_bindings/types.rs index b366c4be..a4b02408 100644 --- a/crates/wdk-sys/generated_bindings/types.rs +++ b/crates/wdk-sys/generated_bindings/types.rs @@ -49930,13 +49930,6 @@ pub struct _IOMMU_DMA_DOMAIN { } pub type IOMMU_DMA_DOMAIN = _IOMMU_DMA_DOMAIN; pub type PIOMMU_DMA_DOMAIN = *mut _IOMMU_DMA_DOMAIN; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _IOMMU_DMA_PASID_DEVICE { - _unused: [u8; 0], -} -pub type IOMMU_DMA_PASID_DEVICE = _IOMMU_DMA_PASID_DEVICE; -pub type PIOMMU_DMA_PASID_DEVICE = *mut _IOMMU_DMA_PASID_DEVICE; pub mod _FAULT_INFORMATION_ARCH { pub type Type = ::core::ffi::c_int; pub const FaultInformationInvalid: Type = 0; @@ -50828,8 +50821,7 @@ pub mod _IOMMU_DMA_DOMAIN_TYPE { pub const DomainTypeTranslate: Type = 0; pub const DomainTypePassThrough: Type = 1; pub const DomainTypeUnmanaged: Type = 2; - pub const DomainTypeTranslateS1: Type = 3; - pub const DomainTypeMax: Type = 4; + pub const DomainTypeMax: Type = 3; } pub use self::_IOMMU_DMA_DOMAIN_TYPE::Type as IOMMU_DMA_DOMAIN_TYPE; pub type PIOMMU_DMA_DOMAIN_TYPE = *mut _IOMMU_DMA_DOMAIN_TYPE::Type; @@ -50930,8 +50922,7 @@ pub mod _IOMMU_DEVICE_CREATION_CONFIGURATION_TYPE { pub const IommuDeviceCreationConfigTypeNone: Type = 0; pub const IommuDeviceCreationConfigTypeAcpi: Type = 1; pub const IommuDeviceCreationConfigTypeDeviceId: Type = 2; - pub const IommuDeviceCreationConfigTypePasid: Type = 3; - pub const IommuDeviceCreationConfigTypeMax: Type = 4; + pub const IommuDeviceCreationConfigTypeMax: Type = 3; } pub use self::_IOMMU_DEVICE_CREATION_CONFIGURATION_TYPE::Type as IOMMU_DEVICE_CREATION_CONFIGURATION_TYPE; pub type PIOMMU_DEVICE_CREATION_CONFIGURATION_TYPE = *mut _IOMMU_DEVICE_CREATION_CONFIGURATION_TYPE::Type; @@ -50980,68 +50971,6 @@ fn bindgen_test_layout__IOMMU_DEVICE_CREATION_CONFIGURATION_ACPI() { } pub type IOMMU_DEVICE_CREATION_CONFIGURATION_ACPI = _IOMMU_DEVICE_CREATION_CONFIGURATION_ACPI; pub type PIOMMU_DEVICE_CREATION_CONFIGURATION_ACPI = *mut _IOMMU_DEVICE_CREATION_CONFIGURATION_ACPI; -pub mod _IOMMU_PASID_CONFIGURATION_TYPE { - pub type Type = ::core::ffi::c_int; - pub const PasidConfigTypeDefaultPasidOnly: Type = 0; - pub const PasidConfigTypePasidTaggedDma: Type = 1; - pub const PasidConfigTypeMax: Type = 2; -} -pub use self::_IOMMU_PASID_CONFIGURATION_TYPE::Type as IOMMU_PASID_CONFIGURATION_TYPE; -pub type PIOMMU_PASID_CONFIGURATION_TYPE = *mut _IOMMU_PASID_CONFIGURATION_TYPE::Type; -#[repr(C)] -#[derive(Debug, Copy, Clone)] -pub struct _IOMMU_DEVICE_CREATION_CONFIGURATION_PASID { - pub ConfigType: IOMMU_PASID_CONFIGURATION_TYPE, - pub SuppressPasidFaults: BOOLEAN, -} -#[test] -fn bindgen_test_layout__IOMMU_DEVICE_CREATION_CONFIGURATION_PASID() { - const UNINIT: ::core::mem::MaybeUninit<_IOMMU_DEVICE_CREATION_CONFIGURATION_PASID> = ::core::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::core::mem::size_of::<_IOMMU_DEVICE_CREATION_CONFIGURATION_PASID>(), - 8usize, - concat!("Size of: ", stringify!(_IOMMU_DEVICE_CREATION_CONFIGURATION_PASID)), - ); - assert_eq!( - ::core::mem::align_of::<_IOMMU_DEVICE_CREATION_CONFIGURATION_PASID>(), - 4usize, - concat!("Alignment of ", stringify!(_IOMMU_DEVICE_CREATION_CONFIGURATION_PASID)), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).ConfigType) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_IOMMU_DEVICE_CREATION_CONFIGURATION_PASID), - "::", - stringify!(ConfigType), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).SuppressPasidFaults) as usize - ptr as usize - }, - 4usize, - concat!( - "Offset of field: ", - stringify!(_IOMMU_DEVICE_CREATION_CONFIGURATION_PASID), - "::", - stringify!(SuppressPasidFaults), - ), - ); -} -impl Default for _IOMMU_DEVICE_CREATION_CONFIGURATION_PASID { - fn default() -> Self { - let mut s = ::core::mem::MaybeUninit::::uninit(); - unsafe { - ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -pub type IOMMU_DEVICE_CREATION_CONFIGURATION_PASID = _IOMMU_DEVICE_CREATION_CONFIGURATION_PASID; -pub type PIOMMU_DEVICE_CREATION_CONFIGURATION_PASID = *mut _IOMMU_DEVICE_CREATION_CONFIGURATION_PASID; #[repr(C)] #[derive(Copy, Clone)] pub struct _IOMMU_DEVICE_CREATION_CONFIGURATION { @@ -51054,7 +50983,6 @@ pub struct _IOMMU_DEVICE_CREATION_CONFIGURATION { pub union _IOMMU_DEVICE_CREATION_CONFIGURATION__bindgen_ty_1 { pub Acpi: IOMMU_DEVICE_CREATION_CONFIGURATION_ACPI, pub DeviceId: PVOID, - pub Pasid: IOMMU_DEVICE_CREATION_CONFIGURATION_PASID, } #[test] fn bindgen_test_layout__IOMMU_DEVICE_CREATION_CONFIGURATION__bindgen_ty_1() { @@ -51098,16 +51026,6 @@ fn bindgen_test_layout__IOMMU_DEVICE_CREATION_CONFIGURATION__bindgen_ty_1() { stringify!(DeviceId), ), ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).Pasid) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_IOMMU_DEVICE_CREATION_CONFIGURATION__bindgen_ty_1), - "::", - stringify!(Pasid), - ), - ); } impl Default for _IOMMU_DEVICE_CREATION_CONFIGURATION__bindgen_ty_1 { fn default() -> Self { @@ -51961,66 +51879,6 @@ pub type IOMMU_INTERFACE_STATE_CHANGE_CALLBACK = ::core::option::Option< unsafe extern "C" fn(StateChange: PIOMMU_INTERFACE_STATE_CHANGE, Context: PVOID), >; pub type PIOMMU_INTERFACE_STATE_CHANGE_CALLBACK = IOMMU_INTERFACE_STATE_CHANGE_CALLBACK; -#[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct _IOMMU_DMA_DEVICE_INFORMATION { - pub DefaultPasidEnabled: BOOLEAN, - pub PasidTaggedDmaEnabled: BOOLEAN, - pub PasidFaultsSuppressed: BOOLEAN, -} -#[test] -fn bindgen_test_layout__IOMMU_DMA_DEVICE_INFORMATION() { - const UNINIT: ::core::mem::MaybeUninit<_IOMMU_DMA_DEVICE_INFORMATION> = ::core::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::core::mem::size_of::<_IOMMU_DMA_DEVICE_INFORMATION>(), - 3usize, - concat!("Size of: ", stringify!(_IOMMU_DMA_DEVICE_INFORMATION)), - ); - assert_eq!( - ::core::mem::align_of::<_IOMMU_DMA_DEVICE_INFORMATION>(), - 1usize, - concat!("Alignment of ", stringify!(_IOMMU_DMA_DEVICE_INFORMATION)), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).DefaultPasidEnabled) as usize - ptr as usize - }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_IOMMU_DMA_DEVICE_INFORMATION), - "::", - stringify!(DefaultPasidEnabled), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).PasidTaggedDmaEnabled) as usize - ptr as usize - }, - 1usize, - concat!( - "Offset of field: ", - stringify!(_IOMMU_DMA_DEVICE_INFORMATION), - "::", - stringify!(PasidTaggedDmaEnabled), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).PasidFaultsSuppressed) as usize - ptr as usize - }, - 2usize, - concat!( - "Offset of field: ", - stringify!(_IOMMU_DMA_DEVICE_INFORMATION), - "::", - stringify!(PasidFaultsSuppressed), - ), - ); -} -pub type IOMMU_DMA_DEVICE_INFORMATION = _IOMMU_DMA_DEVICE_INFORMATION; -pub type PIOMMU_DMA_DEVICE_INFORMATION = *mut _IOMMU_DMA_DEVICE_INFORMATION; pub type IOMMU_DOMAIN_CREATE = ::core::option::Option< unsafe extern "C" fn( OsManagedPageTable: BOOLEAN, @@ -52270,38 +52128,6 @@ pub type IOMMU_SET_DEVICE_FAULT_REPORTING_EX = ::core::option::Option< ) -> NTSTATUS, >; pub type PIOMMU_SET_DEVICE_FAULT_REPORTING_EX = IOMMU_SET_DEVICE_FAULT_REPORTING_EX; -pub type IOMMU_PASID_DEVICE_CREATE = ::core::option::Option< - unsafe extern "C" fn( - DmaDevice: PIOMMU_DMA_DEVICE, - PasidDeviceOut: *mut PIOMMU_DMA_PASID_DEVICE, - AsidOut: PULONG, - ) -> NTSTATUS, ->; -pub type PIOMMU_PASID_DEVICE_CREATE = IOMMU_PASID_DEVICE_CREATE; -pub type IOMMU_PASID_DEVICE_DELETE = ::core::option::Option< - unsafe extern "C" fn(PasidDevice: PIOMMU_DMA_PASID_DEVICE) -> NTSTATUS, ->; -pub type PIOMMU_PASID_DEVICE_DELETE = IOMMU_PASID_DEVICE_DELETE; -pub type IOMMU_DOMAIN_ATTACH_PASID_DEVICE = ::core::option::Option< - unsafe extern "C" fn( - Domain: PIOMMU_DMA_DOMAIN, - PasidDevice: PIOMMU_DMA_PASID_DEVICE, - ) -> NTSTATUS, ->; -pub type PIOMMU_DOMAIN_ATTACH_PASID_DEVICE = IOMMU_DOMAIN_ATTACH_PASID_DEVICE; -pub type IOMMU_DOMAIN_DETACH_PASID_DEVICE = ::core::option::Option< - unsafe extern "C" fn(PasidDevice: PIOMMU_DMA_PASID_DEVICE) -> NTSTATUS, ->; -pub type PIOMMU_DOMAIN_DETACH_PASID_DEVICE = IOMMU_DOMAIN_DETACH_PASID_DEVICE; -pub type IOMMU_DEVICE_QUERY_INFORMATION = ::core::option::Option< - unsafe extern "C" fn( - DmaDevice: PIOMMU_DMA_DEVICE, - Size: ULONG, - BytesWritten: PULONG, - Buffer: PIOMMU_DMA_DEVICE_INFORMATION, - ) -> NTSTATUS, ->; -pub type PIOMMU_DEVICE_QUERY_INFORMATION = IOMMU_DEVICE_QUERY_INFORMATION; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct _DMA_IOMMU_INTERFACE { @@ -52962,367 +52788,6 @@ fn bindgen_test_layout__DMA_IOMMU_INTERFACE_V2() { pub type DMA_IOMMU_INTERFACE_V2 = _DMA_IOMMU_INTERFACE_V2; pub type PDMA_IOMMU_INTERFACE_V2 = *mut _DMA_IOMMU_INTERFACE_V2; #[repr(C)] -#[derive(Debug, Default, Copy, Clone)] -pub struct _DMA_IOMMU_INTERFACE_V3 { - pub CreateDomainEx: PIOMMU_DOMAIN_CREATE_EX, - pub DeleteDomain: PIOMMU_DOMAIN_DELETE, - pub AttachDeviceEx: PIOMMU_DOMAIN_ATTACH_DEVICE_EX, - pub DetachDeviceEx: PIOMMU_DOMAIN_DETACH_DEVICE_EX, - pub FlushDomain: PIOMMU_FLUSH_DOMAIN, - pub FlushDomainByVaList: PIOMMU_FLUSH_DOMAIN_VA_LIST, - pub QueryInputMappings: PIOMMU_QUERY_INPUT_MAPPINGS, - pub MapLogicalRangeEx: PIOMMU_MAP_LOGICAL_RANGE_EX, - pub UnmapLogicalRange: PIOMMU_UNMAP_LOGICAL_RANGE, - pub MapIdentityRangeEx: PIOMMU_MAP_IDENTITY_RANGE_EX, - pub UnmapIdentityRangeEx: PIOMMU_UNMAP_IDENTITY_RANGE_EX, - pub SetDeviceFaultReportingEx: PIOMMU_SET_DEVICE_FAULT_REPORTING_EX, - pub ConfigureDomain: PIOMMU_DOMAIN_CONFIGURE, - pub QueryAvailableDomainTypes: PIOMMU_DEVICE_QUERY_DOMAIN_TYPES, - pub RegisterInterfaceStateChangeCallback: PIOMMU_REGISTER_INTERFACE_STATE_CHANGE_CALLBACK, - pub UnregisterInterfaceStateChangeCallback: PIOMMU_UNREGISTER_INTERFACE_STATE_CHANGE_CALLBACK, - pub ReserveLogicalAddressRange: PIOMMU_RESERVE_LOGICAL_ADDRESS_RANGE, - pub FreeReservedLogicalAddressRange: PIOMMU_FREE_RESERVED_LOGICAL_ADDRESS_RANGE, - pub MapReservedLogicalRange: PIOMMU_MAP_RESERVED_LOGICAL_RANGE, - pub UnmapReservedLogicalRange: PIOMMU_UNMAP_RESERVED_LOGICAL_RANGE, - pub CreateDevice: PIOMMU_DEVICE_CREATE, - pub DeleteDevice: PIOMMU_DEVICE_DELETE, - pub CreatePasidDevice: PIOMMU_PASID_DEVICE_CREATE, - pub DeletePasidDevice: PIOMMU_PASID_DEVICE_DELETE, - pub AttachPasidDevice: PIOMMU_DOMAIN_ATTACH_PASID_DEVICE, - pub DetachPasidDevice: PIOMMU_DOMAIN_DETACH_PASID_DEVICE, - pub QueryDeviceInfo: PIOMMU_DEVICE_QUERY_INFORMATION, -} -#[test] -fn bindgen_test_layout__DMA_IOMMU_INTERFACE_V3() { - const UNINIT: ::core::mem::MaybeUninit<_DMA_IOMMU_INTERFACE_V3> = ::core::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::core::mem::size_of::<_DMA_IOMMU_INTERFACE_V3>(), - 216usize, - concat!("Size of: ", stringify!(_DMA_IOMMU_INTERFACE_V3)), - ); - assert_eq!( - ::core::mem::align_of::<_DMA_IOMMU_INTERFACE_V3>(), - 8usize, - concat!("Alignment of ", stringify!(_DMA_IOMMU_INTERFACE_V3)), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).CreateDomainEx) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(CreateDomainEx), - ), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).DeleteDomain) as usize - ptr as usize }, - 8usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(DeleteDomain), - ), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).AttachDeviceEx) as usize - ptr as usize }, - 16usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(AttachDeviceEx), - ), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).DetachDeviceEx) as usize - ptr as usize }, - 24usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(DetachDeviceEx), - ), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).FlushDomain) as usize - ptr as usize }, - 32usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(FlushDomain), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).FlushDomainByVaList) as usize - ptr as usize - }, - 40usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(FlushDomainByVaList), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).QueryInputMappings) as usize - ptr as usize - }, - 48usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(QueryInputMappings), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).MapLogicalRangeEx) as usize - ptr as usize - }, - 56usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(MapLogicalRangeEx), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).UnmapLogicalRange) as usize - ptr as usize - }, - 64usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(UnmapLogicalRange), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).MapIdentityRangeEx) as usize - ptr as usize - }, - 72usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(MapIdentityRangeEx), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).UnmapIdentityRangeEx) as usize - ptr as usize - }, - 80usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(UnmapIdentityRangeEx), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).SetDeviceFaultReportingEx) as usize - - ptr as usize - }, - 88usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(SetDeviceFaultReportingEx), - ), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).ConfigureDomain) as usize - ptr as usize }, - 96usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(ConfigureDomain), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).QueryAvailableDomainTypes) as usize - - ptr as usize - }, - 104usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(QueryAvailableDomainTypes), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).RegisterInterfaceStateChangeCallback) as usize - - ptr as usize - }, - 112usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(RegisterInterfaceStateChangeCallback), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).UnregisterInterfaceStateChangeCallback) as usize - - ptr as usize - }, - 120usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(UnregisterInterfaceStateChangeCallback), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).ReserveLogicalAddressRange) as usize - - ptr as usize - }, - 128usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(ReserveLogicalAddressRange), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).FreeReservedLogicalAddressRange) as usize - - ptr as usize - }, - 136usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(FreeReservedLogicalAddressRange), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).MapReservedLogicalRange) as usize - ptr as usize - }, - 144usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(MapReservedLogicalRange), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).UnmapReservedLogicalRange) as usize - - ptr as usize - }, - 152usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(UnmapReservedLogicalRange), - ), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).CreateDevice) as usize - ptr as usize }, - 160usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(CreateDevice), - ), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).DeleteDevice) as usize - ptr as usize }, - 168usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(DeleteDevice), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).CreatePasidDevice) as usize - ptr as usize - }, - 176usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(CreatePasidDevice), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).DeletePasidDevice) as usize - ptr as usize - }, - 184usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(DeletePasidDevice), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).AttachPasidDevice) as usize - ptr as usize - }, - 192usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(AttachPasidDevice), - ), - ); - assert_eq!( - unsafe { - ::core::ptr::addr_of!((*ptr).DetachPasidDevice) as usize - ptr as usize - }, - 200usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(DetachPasidDevice), - ), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).QueryDeviceInfo) as usize - ptr as usize }, - 208usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_V3), - "::", - stringify!(QueryDeviceInfo), - ), - ); -} -pub type DMA_IOMMU_INTERFACE_V3 = _DMA_IOMMU_INTERFACE_V3; -pub type PDMA_IOMMU_INTERFACE_V3 = *mut _DMA_IOMMU_INTERFACE_V3; -#[repr(C)] #[derive(Copy, Clone)] pub struct _DMA_IOMMU_INTERFACE_EX { pub Size: SIZE_T, @@ -53334,7 +52799,6 @@ pub struct _DMA_IOMMU_INTERFACE_EX { pub union _DMA_IOMMU_INTERFACE_EX__bindgen_ty_1 { pub V1: DMA_IOMMU_INTERFACE_V1, pub V2: DMA_IOMMU_INTERFACE_V2, - pub V3: DMA_IOMMU_INTERFACE_V3, } #[test] fn bindgen_test_layout__DMA_IOMMU_INTERFACE_EX__bindgen_ty_1() { @@ -53342,7 +52806,7 @@ fn bindgen_test_layout__DMA_IOMMU_INTERFACE_EX__bindgen_ty_1() { let ptr = UNINIT.as_ptr(); assert_eq!( ::core::mem::size_of::<_DMA_IOMMU_INTERFACE_EX__bindgen_ty_1>(), - 216usize, + 176usize, concat!("Size of: ", stringify!(_DMA_IOMMU_INTERFACE_EX__bindgen_ty_1)), ); assert_eq!( @@ -53370,16 +52834,6 @@ fn bindgen_test_layout__DMA_IOMMU_INTERFACE_EX__bindgen_ty_1() { stringify!(V2), ), ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).V3) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!(_DMA_IOMMU_INTERFACE_EX__bindgen_ty_1), - "::", - stringify!(V3), - ), - ); } impl Default for _DMA_IOMMU_INTERFACE_EX__bindgen_ty_1 { fn default() -> Self { @@ -53396,7 +52850,7 @@ fn bindgen_test_layout__DMA_IOMMU_INTERFACE_EX() { let ptr = UNINIT.as_ptr(); assert_eq!( ::core::mem::size_of::<_DMA_IOMMU_INTERFACE_EX>(), - 232usize, + 192usize, concat!("Size of: ", stringify!(_DMA_IOMMU_INTERFACE_EX)), ); assert_eq!( @@ -80209,8 +79663,7 @@ pub mod _PROCESS_MITIGATION_POLICY { pub const ProcessRedirectionTrustPolicy: Type = 16; pub const ProcessUserPointerAuthPolicy: Type = 17; pub const ProcessSEHOPPolicy: Type = 18; - pub const ProcessActivationContextTrustPolicy: Type = 19; - pub const MaxProcessMitigationPolicy: Type = 20; + pub const MaxProcessMitigationPolicy: Type = 19; } pub use self::_PROCESS_MITIGATION_POLICY::Type as PROCESS_MITIGATION_POLICY; pub type PPROCESS_MITIGATION_POLICY = *mut _PROCESS_MITIGATION_POLICY::Type; @@ -84374,183 +83827,6 @@ impl Default for _PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY { pub type PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY = _PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY; pub type PPROCESS_MITIGATION_REDIRECTION_TRUST_POLICY = *mut _PROCESS_MITIGATION_REDIRECTION_TRUST_POLICY; #[repr(C)] -#[derive(Copy, Clone)] -pub struct _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY { - pub __bindgen_anon_1: _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1, -} -#[repr(C)] -#[derive(Copy, Clone)] -pub union _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1 { - pub Flags: ULONG, - pub __bindgen_anon_1: _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1__bindgen_ty_1, -} -#[repr(C)] -#[repr(align(4))] -#[derive(Debug, Default, Copy, Clone)] -pub struct _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1__bindgen_ty_1 { - pub _bitfield_align_1: [u32; 0], - pub _bitfield_1: __BindgenBitfieldUnit<[u8; 4usize]>, -} -#[test] -fn bindgen_test_layout__PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1__bindgen_ty_1() { - assert_eq!( - ::core::mem::size_of::< - _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1__bindgen_ty_1, - >(), - 4usize, - concat!( - "Size of: ", - stringify!( - _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1__bindgen_ty_1 - ), - ), - ); - assert_eq!( - ::core::mem::align_of::< - _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1__bindgen_ty_1, - >(), - 4usize, - concat!( - "Alignment of ", - stringify!( - _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1__bindgen_ty_1 - ), - ), - ); -} -impl _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1__bindgen_ty_1 { - #[inline] - pub fn AssemblyManifestRedirectionTrust(&self) -> ULONG { - unsafe { ::core::mem::transmute(self._bitfield_1.get(0usize, 1u8) as u32) } - } - #[inline] - pub fn set_AssemblyManifestRedirectionTrust(&mut self, val: ULONG) { - unsafe { - let val: u32 = ::core::mem::transmute(val); - self._bitfield_1.set(0usize, 1u8, val as u64) - } - } - #[inline] - pub fn ReservedFlags(&self) -> ULONG { - unsafe { ::core::mem::transmute(self._bitfield_1.get(1usize, 31u8) as u32) } - } - #[inline] - pub fn set_ReservedFlags(&mut self, val: ULONG) { - unsafe { - let val: u32 = ::core::mem::transmute(val); - self._bitfield_1.set(1usize, 31u8, val as u64) - } - } - #[inline] - pub fn new_bitfield_1( - AssemblyManifestRedirectionTrust: ULONG, - ReservedFlags: ULONG, - ) -> __BindgenBitfieldUnit<[u8; 4usize]> { - let mut __bindgen_bitfield_unit: __BindgenBitfieldUnit<[u8; 4usize]> = Default::default(); - __bindgen_bitfield_unit - .set( - 0usize, - 1u8, - { - let AssemblyManifestRedirectionTrust: u32 = unsafe { - ::core::mem::transmute(AssemblyManifestRedirectionTrust) - }; - AssemblyManifestRedirectionTrust as u64 - }, - ); - __bindgen_bitfield_unit - .set( - 1usize, - 31u8, - { - let ReservedFlags: u32 = unsafe { - ::core::mem::transmute(ReservedFlags) - }; - ReservedFlags as u64 - }, - ); - __bindgen_bitfield_unit - } -} -#[test] -fn bindgen_test_layout__PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1() { - const UNINIT: ::core::mem::MaybeUninit< - _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1, - > = ::core::mem::MaybeUninit::uninit(); - let ptr = UNINIT.as_ptr(); - assert_eq!( - ::core::mem::size_of::< - _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1, - >(), - 4usize, - concat!( - "Size of: ", - stringify!(_PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1), - ), - ); - assert_eq!( - ::core::mem::align_of::< - _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1, - >(), - 4usize, - concat!( - "Alignment of ", - stringify!(_PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1), - ), - ); - assert_eq!( - unsafe { ::core::ptr::addr_of!((*ptr).Flags) as usize - ptr as usize }, - 0usize, - concat!( - "Offset of field: ", - stringify!( - _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1 - ), - "::", - stringify!(Flags), - ), - ); -} -impl Default for _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY__bindgen_ty_1 { - fn default() -> Self { - let mut s = ::core::mem::MaybeUninit::::uninit(); - unsafe { - ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -#[test] -fn bindgen_test_layout__PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY() { - assert_eq!( - ::core::mem::size_of::<_PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY>(), - 4usize, - concat!( - "Size of: ", - stringify!(_PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY), - ), - ); - assert_eq!( - ::core::mem::align_of::<_PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY>(), - 4usize, - concat!( - "Alignment of ", - stringify!(_PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY), - ), - ); -} -impl Default for _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY { - fn default() -> Self { - let mut s = ::core::mem::MaybeUninit::::uninit(); - unsafe { - ::core::ptr::write_bytes(s.as_mut_ptr(), 0, 1); - s.assume_init() - } - } -} -pub type PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY = _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY; -pub type PPROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY = *mut _PROCESS_MITIGATION_ACTIVATION_CONTEXT_TRUST_POLICY; -#[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct _PROCESS_KEEPALIVE_COUNT_INFORMATION { pub WakeCount: ULONG, diff --git a/crates/wdk-sys/src/constants.rs b/crates/wdk-sys/src/constants.rs index dddec3c5..81e24957 100644 --- a/crates/wdk-sys/src/constants.rs +++ b/crates/wdk-sys/src/constants.rs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +#![allow(missing_docs)] + use crate::types::{NTSTATUS, POOL_FLAGS, PVOID, PWDF_OBJECT_ATTRIBUTES}; #[allow(non_upper_case_globals)] diff --git a/crates/wdk-sys/src/lib.rs b/crates/wdk-sys/src/lib.rs index 472c7b36..8deb561d 100644 --- a/crates/wdk-sys/src/lib.rs +++ b/crates/wdk-sys/src/lib.rs @@ -1,12 +1,26 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +//! Direct bindings to APIs available in the Windows Development Kit (WDK) + #![no_std] #![deny(warnings)] +#![deny(missing_docs)] #![deny(clippy::all)] #![deny(clippy::pedantic)] #![deny(clippy::nursery)] #![deny(clippy::cargo)] +#![deny(clippy::undocumented_unsafe_blocks)] +#![deny(clippy::unnecessary_safety_doc)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] +#![deny(rustdoc::missing_crate_level_docs)] +#![deny(rustdoc::invalid_codeblock_attributes)] +#![deny(rustdoc::invalid_html_tags)] +#![deny(rustdoc::invalid_rust_codeblocks)] +#![deny(rustdoc::bare_urls)] +#![deny(rustdoc::unescaped_backticks)] +#![deny(rustdoc::redundant_explicit_links)] mod constants; mod types; @@ -26,10 +40,12 @@ use lazy_static::lazy_static; // our binary, thanks to our target defining soft-floats. fltused symbol is // necessary due to LLVM being too eager to set it: it checks the LLVM IR for // floating point instructions - even if soft-float is enabled! +#[allow(missing_docs)] #[no_mangle] pub static _fltused: () = (); // FIXME: Is there any way to avoid this stub? See https://github.com/rust-lang/rust/issues/101134 +#[allow(missing_docs)] #[allow(clippy::missing_const_for_fn)] // const extern is not yet supported: https://github.com/rust-lang/rust/issues/64926 #[no_mangle] pub extern "system" fn __CxxFrameHandler3() -> i32 { @@ -39,16 +55,35 @@ pub extern "system" fn __CxxFrameHandler3() -> i32 { // FIXME: dynamically find name of this struct based off of wdk-build settings // FIXME: replace lazy_static with std::Lazy once available: https://github.com/rust-lang/rust/issues/109736 lazy_static! { - pub static ref WDF_FUNCTION_TABLE: &'static [WDFFUNC] = - unsafe { core::slice::from_raw_parts(WdfFunctions_01033, WdfFunctionCount as usize) }; + #[allow(missing_docs)] + pub static ref WDF_FUNCTION_TABLE: &'static [WDFFUNC] = { + debug_assert!( + isize::try_from( + // SAFETY: `WdfFunctionCount` is generated as a mutable static, but is not supposed to be mutated by WDF. + unsafe { WdfFunctionCount } as usize * core::mem::size_of::() + ).is_ok() + ); + + // SAFETY: This is safe because: + // 1. `WdfFunctions_01033` is valid for reads for `WdfFunctionCount` * `core::mem::size_of::()` + // bytes, and is guaranteed to be aligned and it must be properly aligned. + // 2. `WdfFunctions_01033` points to `WdfFunctionCount` consecutive properly initialized values of + // type `WDFFUNC`. + // 3. WDF does not mutate the memory referenced by the returned slice for for its entire `'static' lifetime. + // 4. The total size, `WdfFunctionCount` * `core::mem::size_of::()`, of the slice must be no + // larger than `isize::MAX`. This is proven by the above `debug_assert!`. + unsafe { core::slice::from_raw_parts(WdfFunctions_01033, WdfFunctionCount as usize) } + }; } +#[allow(missing_docs)] #[must_use] #[allow(non_snake_case)] pub const fn NT_SUCCESS(nt_status: NTSTATUS) -> bool { nt_status >= 0 } +#[allow(missing_docs)] #[macro_export] #[allow(non_snake_case)] macro_rules! PAGED_CODE { diff --git a/crates/wdk-sys/src/macros.rs b/crates/wdk-sys/src/macros.rs index 75abadf3..af7d39a8 100644 --- a/crates/wdk-sys/src/macros.rs +++ b/crates/wdk-sys/src/macros.rs @@ -1,4 +1,8 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +//! Macros for use in the `wdk-sys` crate. This is especially useful for +//! interacting with WDK apis which are inlined, and so are impossible to +//! generate with [bindgen](https://docs.rs/bindgen/latest/bindgen/). + pub use wdk_macros::*; diff --git a/crates/wdk-sys/src/ntddk.rs b/crates/wdk-sys/src/ntddk.rs index 16bc8e9a..d4a44ecc 100644 --- a/crates/wdk-sys/src/ntddk.rs +++ b/crates/wdk-sys/src/ntddk.rs @@ -1,6 +1,8 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +#![allow(missing_docs)] + // allow wildcards for types module since underlying c code relies on all // type definitions being in scope #[allow(clippy::wildcard_imports)] diff --git a/crates/wdk-sys/src/types.rs b/crates/wdk-sys/src/types.rs index aadaf45c..35cacbaa 100644 --- a/crates/wdk-sys/src/types.rs +++ b/crates/wdk-sys/src/types.rs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +#[allow(missing_docs)] #[allow(non_upper_case_globals)] #[allow(non_camel_case_types)] #[allow(non_snake_case)] @@ -20,6 +21,7 @@ #[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_lines)] #[allow(clippy::transmute_ptr_to_ptr)] +#[allow(clippy::undocumented_unsafe_blocks)] #[allow(clippy::unnecessary_cast)] #[allow(clippy::unreadable_literal)] #[allow(clippy::used_underscore_binding)] diff --git a/crates/wdk-sys/src/wdf.rs b/crates/wdk-sys/src/wdf.rs index d504bca5..2a6615af 100644 --- a/crates/wdk-sys/src/wdf.rs +++ b/crates/wdk-sys/src/wdf.rs @@ -1,7 +1,11 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +//! Direct FFI bindings to WDF APIs from the Windows Driver Kit (WDK) + use crate::types::ULONG; + +#[allow(missing_docs)] #[allow(clippy::unreadable_literal)] mod bindings { // allow wildcards for types module since underlying c code relies on all diff --git a/crates/wdk/src/lib.rs b/crates/wdk/src/lib.rs index c17fddac..daef75e8 100644 --- a/crates/wdk/src/lib.rs +++ b/crates/wdk/src/lib.rs @@ -1,13 +1,28 @@ // Copyright (c) Microsoft Corporation // License: MIT OR Apache-2.0 +//! Idiomatic Rust wrappers for the Windows Driver Kit (WDK) APIs. This crate is +//! built on top of the raw FFI bindings provided by [`wdk-sys`], and provides a +//! safe, idiomatic rust interface to the WDK. #![no_std] #![cfg_attr(feature = "nightly", feature(hint_must_use))] #![deny(warnings)] +#![deny(missing_docs)] #![deny(clippy::all)] #![deny(clippy::pedantic)] #![deny(clippy::nursery)] #![deny(clippy::cargo)] +#![deny(clippy::undocumented_unsafe_blocks)] +#![deny(clippy::unnecessary_safety_doc)] +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(rustdoc::private_intra_doc_links)] +#![deny(rustdoc::missing_crate_level_docs)] +#![deny(rustdoc::invalid_codeblock_attributes)] +#![deny(rustdoc::invalid_html_tags)] +#![deny(rustdoc::invalid_rust_codeblocks)] +#![deny(rustdoc::bare_urls)] +#![deny(rustdoc::unescaped_backticks)] +#![deny(rustdoc::redundant_explicit_links)] #[cfg(feature = "alloc")] mod print; @@ -21,6 +36,7 @@ pub mod wdf; /// # Panics /// Will Panic if called on an unsupported architecture pub fn dbg_break() { + // SAFETY: Abides all rules outlined in https://doc.rust-lang.org/reference/inline-assembly.html#rules-for-inline-assembly unsafe { #[cfg(target_arch = "aarch64")] { diff --git a/crates/wdk/src/print.rs b/crates/wdk/src/print.rs index 8fce6f4e..f994578e 100644 --- a/crates/wdk/src/print.rs +++ b/crates/wdk/src/print.rs @@ -7,6 +7,7 @@ use alloc::ffi::CString; use wdk_sys::ntddk::DbgPrint; +/// print to kernel debugger via [`wdk_sys::ntddk::DbgPrint`] #[macro_export] macro_rules! print { ($($arg:tt)*) => { @@ -14,6 +15,7 @@ macro_rules! print { }; } +/// print with newline to debugger via [`wdk_sys::ntddk::DbgPrint`] #[macro_export] macro_rules! println { () => { @@ -24,6 +26,7 @@ macro_rules! println { ($crate::print!("{}\n", format_args!($($arg)*))) }; } + /// Internal implementation of print macros. This function is an implementation /// detail and should never be called directly, but must be public to be useable /// by the print! and println! macro @@ -36,6 +39,7 @@ pub fn _print(args: core::fmt::Arguments) { let formatted_string = CString::new(alloc::format!("{args}")) .expect("CString should be able to be created from a String."); + // SAFETY: `formatted_string` is a valid null terminated string unsafe { DbgPrint(formatted_string.as_ptr()); } diff --git a/crates/wdk/src/wdf/mod.rs b/crates/wdk/src/wdf/mod.rs index 8e4880e3..f8bb3347 100644 --- a/crates/wdk/src/wdf/mod.rs +++ b/crates/wdk/src/wdf/mod.rs @@ -1,3 +1,5 @@ +//! Safe abstractions over WDF APIs + mod spinlock; mod timer; diff --git a/crates/wdk/src/wdf/spinlock.rs b/crates/wdk/src/wdf/spinlock.rs index afae06c0..c047db08 100644 --- a/crates/wdk/src/wdf/spinlock.rs +++ b/crates/wdk/src/wdf/spinlock.rs @@ -2,8 +2,22 @@ use wdk_sys::{macros, NTSTATUS, WDFSPINLOCK, WDF_OBJECT_ATTRIBUTES}; use crate::nt_success; -#[allow(clippy::module_name_repetitions)] // private module + public re-export avoids the module name repetition: https://github.com/rust-lang/rust-clippy/issues/8524 +#[allow(clippy::module_name_repetitions)] + +/// WDF Spin Lock. +/// +/// Use framework spin locks to synchronize access to driver data from code that +/// runs at `IRQL` <= `DISPATCH_LEVEL`. When a driver thread acquires a spin +/// lock, the system sets the thread's IRQL to `DISPATCH_LEVEL`. When the thread +/// releases the lock, the system restores the thread's IRQL to its previous +/// level. A driver that is not using automatic framework synchronization might +/// use a spin lock to synchronize access to a device object's context space, if +/// the context space is writable and if more than one of the driver's event +/// callback functions access the space. Before a driver can use a framework +/// spin lock it must call [`SpinLock::try_new()`] to create a [`SpinLock`]. The +/// driver can then call [`SpinLock::acquire`] to acquire the lock and +/// [`SpinLock::release()`] to release it. pub struct SpinLock { wdf_spin_lock: WDFSPINLOCK, } @@ -17,13 +31,15 @@ impl SpinLock { let mut spin_lock = Self { wdf_spin_lock: core::ptr::null_mut(), }; - let nt_status = unsafe { - macros::call_unsafe_wdf_function_binding!( - WdfSpinLockCreate, - attributes, - &mut spin_lock.wdf_spin_lock, - ) - }; + let nt_status = + // SAFETY: The resulting ffi object is stored in a private member and not accessible outside of this module, and this module guarantees that it is always in a valid state. + unsafe { + macros::call_unsafe_wdf_function_binding!( + WdfSpinLockCreate, + attributes, + &mut spin_lock.wdf_spin_lock, + ) + }; nt_success(nt_status).then_some(spin_lock).ok_or(nt_status) } @@ -37,21 +53,27 @@ impl SpinLock { Self::try_new(attributes) } + /// Acquire the spinlock pub fn acquire(&self) { - let [()] = unsafe { - [macros::call_unsafe_wdf_function_binding!( - WdfSpinLockAcquire, - self.wdf_spin_lock - )] - }; + let [()] = + // SAFETY: `wdf_spin_lock` is a private member of `SpinLock`, originally created by WDF, and this module guarantees that it is always in a valid state. + unsafe { + [macros::call_unsafe_wdf_function_binding!( + WdfSpinLockAcquire, + self.wdf_spin_lock + )] + }; } + /// Release the spinlock pub fn release(&self) { - let [()] = unsafe { - [macros::call_unsafe_wdf_function_binding!( - WdfSpinLockRelease, - self.wdf_spin_lock - )] - }; + let [()] = + // SAFETY: `wdf_spin_lock` is a private member of `SpinLock`, originally created by WDF, and this module guarantees that it is always in a valid state. + unsafe { + [macros::call_unsafe_wdf_function_binding!( + WdfSpinLockRelease, + self.wdf_spin_lock + )] + }; } } diff --git a/crates/wdk/src/wdf/timer.rs b/crates/wdk/src/wdf/timer.rs index e5891682..237e8ebb 100644 --- a/crates/wdk/src/wdf/timer.rs +++ b/crates/wdk/src/wdf/timer.rs @@ -2,8 +2,10 @@ use wdk_sys::{macros, NTSTATUS, WDFTIMER, WDF_OBJECT_ATTRIBUTES, WDF_TIMER_CONFI use crate::nt_success; -#[allow(clippy::module_name_repetitions)] // private module + public re-export avoids the module name repetition: https://github.com/rust-lang/rust-clippy/issues/8524 +#[allow(clippy::module_name_repetitions)] + +/// WDF Timer. pub struct Timer { wdf_timer: WDFTIMER, } @@ -20,14 +22,16 @@ impl Timer { let mut timer = Self { wdf_timer: core::ptr::null_mut(), }; - let nt_status = unsafe { - macros::call_unsafe_wdf_function_binding!( - WdfTimerCreate, - timer_config, - attributes, - &mut timer.wdf_timer, - ) - }; + let nt_status = + // SAFETY: The resulting ffi object is stored in a private member and not accessible outside of this module, and this module guarantees that it is always in a valid state. + unsafe { + macros::call_unsafe_wdf_function_binding!( + WdfTimerCreate, + timer_config, + attributes, + &mut timer.wdf_timer, + ) + }; nt_success(nt_status).then_some(timer).ok_or(nt_status) } @@ -43,17 +47,23 @@ impl Timer { Self::try_new(timer_config, attributes) } + /// Start the [`Timer`]'s clock pub fn start(&self, due_time: i64) -> bool { - let result = unsafe { - macros::call_unsafe_wdf_function_binding!(WdfTimerStart, self.wdf_timer, due_time) - }; + let result = + // SAFETY: `wdf_timer` is a private member of `Timer`, originally created by WDF, and this module guarantees that it is always in a valid state. + unsafe { + macros::call_unsafe_wdf_function_binding!(WdfTimerStart, self.wdf_timer, due_time) + }; result != 0 } + /// Stop the [`Timer`]'s clock pub fn stop(&self, wait: bool) -> bool { - let result = unsafe { - macros::call_unsafe_wdf_function_binding!(WdfTimerStop, self.wdf_timer, u8::from(wait)) - }; + let result = + // SAFETY: `wdf_timer` is a private member of `Timer`, originally created by WDF, and this module guarantees that it is always in a valid state. + unsafe { + macros::call_unsafe_wdf_function_binding!(WdfTimerStop, self.wdf_timer, u8::from(wait)) + }; result != 0 } }