diff --git a/packaging/windows/drivers/Cargo.lock b/packaging/windows/drivers/Cargo.lock index 8dc5efd..1934618 100644 --- a/packaging/windows/drivers/Cargo.lock +++ b/packaging/windows/drivers/Cargo.lock @@ -394,6 +394,17 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pf-vdisplay" +version = "0.0.1" +dependencies = [ + "pf-vdisplay-proto", + "wdk", + "wdk-build", + "wdk-iddcx", + "wdk-sys", +] + [[package]] name = "pf-vdisplay-proto" version = "0.0.1" @@ -735,6 +746,13 @@ dependencies = [ "windows", ] +[[package]] +name = "wdk-iddcx" +version = "0.0.1" +dependencies = [ + "wdk-sys", +] + [[package]] name = "wdk-macros" version = "0.5.1" diff --git a/packaging/windows/drivers/Cargo.toml b/packaging/windows/drivers/Cargo.toml index f406a9b..2421752 100644 --- a/packaging/windows/drivers/Cargo.toml +++ b/packaging/windows/drivers/Cargo.toml @@ -7,7 +7,7 @@ # crates/pf-vdisplay-proto from the main tree. [workspace] resolver = "2" -members = ["wdk-probe"] +members = ["wdk-probe", "wdk-iddcx", "pf-vdisplay"] [workspace.package] edition = "2024" @@ -19,6 +19,7 @@ publish = false wdk = "0.4.1" wdk-sys = "0.5.1" wdk-build = "0.5.1" +wdk-iddcx = { path = "wdk-iddcx" } pf-vdisplay-proto = { path = "../../../crates/pf-vdisplay-proto" } # Vendored windows-drivers-rs 0.5.1 (the published, self-contained crates) + an added `iddcx` diff --git a/packaging/windows/drivers/pf-vdisplay/Cargo.toml b/packaging/windows/drivers/pf-vdisplay/Cargo.toml new file mode 100644 index 0000000..4d8c754 --- /dev/null +++ b/packaging/windows/drivers/pf-vdisplay/Cargo.toml @@ -0,0 +1,26 @@ +# pf-vdisplay — the all-Rust UMDF IddCx virtual-display driver (M1 step-2 rewrite onto wdk-sys + the +# owned pf-vdisplay-proto ABI). Replaces the vendored-binding oracle at packaging/windows/vdisplay-driver/ +# (deleted once on-glass parity is reached, per docs/windows-host-rewrite.md §14 STEP 8). +[package] +name = "pf-vdisplay" +edition.workspace = true +version.workspace = true +license.workspace = true +publish = false + +[package.metadata.wdk.driver-model] +driver-type = "UMDF" +umdf-version-major = 2 +target-umdf-version-minor = 31 + +[lib] +crate-type = ["cdylib"] + +[build-dependencies] +wdk-build.workspace = true + +[dependencies] +wdk.workspace = true +wdk-sys = { workspace = true, features = ["iddcx"] } +wdk-iddcx.workspace = true +pf-vdisplay-proto.workspace = true diff --git a/packaging/windows/drivers/pf-vdisplay/build.rs b/packaging/windows/drivers/pf-vdisplay/build.rs new file mode 100644 index 0000000..6ccf3f9 --- /dev/null +++ b/packaging/windows/drivers/pf-vdisplay/build.rs @@ -0,0 +1,6 @@ +//! Emits the WDK link flags for the cdylib (wdk-build). STEP 0 needs only the WDF stub link + the +//! `/INTEGRITYCHECK` that the CI step clears; `IddCxStub` (+ `IddMinimumVersionRequired`) is added in +//! STEP 2 when the driver actually calls IddCx — see wdk-probe/build.rs for the glob recipe. +fn main() -> Result<(), wdk_build::ConfigError> { + wdk_build::configure_wdk_binary_build() +} diff --git a/packaging/windows/drivers/pf-vdisplay/src/lib.rs b/packaging/windows/drivers/pf-vdisplay/src/lib.rs new file mode 100644 index 0000000..8607e78 --- /dev/null +++ b/packaging/windows/drivers/pf-vdisplay/src/lib.rs @@ -0,0 +1,70 @@ +//! pf-vdisplay — the all-Rust UMDF IddCx virtual-display driver (M1 step-2 rewrite, on wdk-sys + the +//! owned pf-vdisplay-proto ABI). See docs/windows-host-rewrite.md §14 for the full port plan. +//! +//! STEP 0 (this commit): the workspace scaffold + the std-under-UMDF LINK GATE. DriverEntry → +//! WdfDriverCreate → (EvtDeviceAdd) WdfDeviceCreate, plus a `#[used]` probe that forces `std::thread` +//! + `OwnedHandle` to link — the SwapChainProcessor (STEP 5) depends on both, and the wdk-build UMDF +//! link settings `/NODEFAULTLIB:kernel32.lib`, so std must resolve via OneCoreUAP. If this fails to +//! link, the worker-thread/handle design needs a CreateThread shim BEFORE any callback work (port-plan +//! critique gap #9). The adapter/monitor/swapchain/IDD-push logic lands in STEP 2-6. + +#![allow(non_snake_case, clippy::missing_safety_doc)] + +use wdk_sys::{ + call_unsafe_wdf_function_binding, NTSTATUS, PCUNICODE_STRING, PDRIVER_OBJECT, PWDFDEVICE_INIT, + ULONG, WDFDEVICE, WDFDRIVER, WDF_DRIVER_CONFIG, WDF_NO_HANDLE, WDF_NO_OBJECT_ATTRIBUTES, +}; + +const STATUS_SUCCESS: NTSTATUS = 0; + +/// STEP-0 link gate (port-plan critique #9). Forces `std::thread` + `std::os::windows::io::OwnedHandle` +/// to be linked into the UMDF cdylib so STEP 0's `cargo build` actually proves the std surface resolves +/// under the wdk-build link settings (kernel32 is `/NODEFAULTLIB`'d → std must come via OneCoreUAP). +/// Never called; `#[used]` keeps the symbol so the linker pulls std. Also touches `wdk-iddcx` to prove +/// the pf-vdisplay → wdk-iddcx → wdk-sys/iddcx dependency graph resolves. +fn _std_link_gate() { + use std::os::windows::io::OwnedHandle; + let t = std::thread::spawn(|| 0u32); + let _ = t.join(); + let _drop_owned: fn(OwnedHandle) = core::mem::drop; + // touch the iddcx surface via wdk-iddcx (forces the feature-enabled dep graph) + let _adapter: Option = None; +} +#[used] +static _STD_LINK_GATE: fn() = _std_link_gate; + +#[unsafe(export_name = "DriverEntry")] +pub unsafe extern "system" fn driver_entry( + driver: PDRIVER_OBJECT, + registry_path: PCUNICODE_STRING, +) -> NTSTATUS { + // SAFETY: zeroed then Size + the device-add callback set, per the WDF_DRIVER_CONFIG contract. + let mut config: WDF_DRIVER_CONFIG = unsafe { core::mem::zeroed() }; + config.Size = core::mem::size_of::() as ULONG; + config.EvtDriverDeviceAdd = Some(evt_device_add); + // SAFETY: driver + registry_path are loader-provided; config is valid for the call. + unsafe { + call_unsafe_wdf_function_binding!( + WdfDriverCreate, + driver, + registry_path, + WDF_NO_OBJECT_ATTRIBUTES, + &mut config, + WDF_NO_HANDLE.cast::() + ) + } +} + +extern "C" fn evt_device_add(_driver: WDFDRIVER, mut device_init: PWDFDEVICE_INIT) -> NTSTATUS { + let mut device: WDFDEVICE = core::ptr::null_mut(); + // SAFETY: device_init is the framework-provided init; attributes null; device receives the handle. + let _ = unsafe { + call_unsafe_wdf_function_binding!( + WdfDeviceCreate, + &mut device_init, + WDF_NO_OBJECT_ATTRIBUTES, + &mut device + ) + }; + STATUS_SUCCESS +} diff --git a/packaging/windows/drivers/wdk-iddcx/Cargo.toml b/packaging/windows/drivers/wdk-iddcx/Cargo.toml new file mode 100644 index 0000000..f22a945 --- /dev/null +++ b/packaging/windows/drivers/wdk-iddcx/Cargo.toml @@ -0,0 +1,14 @@ +# Safe-ish typed wrappers over the wdk-sys IddCx DDIs (table dispatch). Graduates the proven dispatch +# from wdk-probe/src/iddcx_rt.rs (M1 step 1) into a reusable crate the pf-vdisplay driver depends on. +# A plain lib (rlib) — no build.rs; it rides on wdk-sys's iddcx bindgen. +[package] +name = "wdk-iddcx" +edition.workspace = true +version.workspace = true +license.workspace = true +publish = false + +[lib] + +[dependencies] +wdk-sys = { workspace = true, features = ["iddcx"] } diff --git a/packaging/windows/drivers/wdk-iddcx/src/lib.rs b/packaging/windows/drivers/wdk-iddcx/src/lib.rs new file mode 100644 index 0000000..00f9eb0 --- /dev/null +++ b/packaging/windows/drivers/wdk-iddcx/src/lib.rs @@ -0,0 +1,11 @@ +//! Safe-ish typed wrappers over the wdk-sys IddCx DDIs, dispatched through the `IddFunctions` table +//! (indexed by `_IDDFUNCENUM::TableIndex`, with `IddDriverGlobals` as the implicit first arg) — +//! the same model wdk-sys uses for WDF. Graduates the proven dispatch from `wdk-probe/src/iddcx_rt.rs` +//! (M1 step 1) into the crate the pf-vdisplay driver builds on. +//! +//! STEP 0: re-export the wdk-sys `iddcx` module so the crate + the `iddcx` feature resolve in the +//! workspace. STEP 1 adds the 11 typed DDI wrappers (one fixed `(_IDDFUNCENUM index, PFN_*)` pair per +//! site) + `is_nt_error`/`other_is_error` + the inbound `PFN_IDD_CX_*` callback-type re-exports. +#![no_std] + +pub use wdk_sys::iddcx;