feat(windows-drivers): STEP 3 on-glass — driver LOADS + runs full IddCx init chain
Major on-glass progress on the RTX box. The all-Rust wdk-sys IddCx driver now LOADS under Secure Boot and runs the ENTIRE init chain: DriverEntry -> WdfDriverCreate -> driver_add -> IddCxDeviceInitConfig(0x0) -> WdfDeviceCreate -> CreateDeviceInterface -> IddCxDeviceInitialize -> D0Entry -> init_adapter. Findings: - Signing was a RED HERRING (the driver loads); std works in WUDFHost (DualSense uses it too). - THE unblock: link the iddcx **1.10** IddCxStub (build.rs now picks the highest version-aware), not 1.0 — the 1.0 stub lacks the version-table symbols AND its dispatch table mismatched the 1.10 framework, which made IddCxDeviceInitConfig return INVALID_PARAMETER. With 1.10 the whole chain runs. - Added a file/OutputDebugString logger (log.rs, matches the DualSense driver) — the driver was silent; this is how the chain was traced. - size.rs: framework_struct_size() reads the frameworks authoritative struct sizes from IddStructures[] (the config keeps size_of=208, validated working). - adapter.rs: version ptrs + ObjectAttributes(InheritFromParent) + FP16 + framework caps/diag/version sizes — matches the oracle. KNOWN WIP: IddCxAdapterInitAsync still returns INVALID_PARAMETER though caps match the framework size table (88/56/24) + the oracle exactly — likely a subtle wdk-sys bindgen field-layout detail in IDDCX_ADAPTER_CAPS/IDDCX_ENDPOINT_DIAGNOSTIC_INFO. CI gate (compile+link) stays green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,19 +1,59 @@
|
||||
//! `.Size` for `IDD_CX_CLIENT_CONFIG`.
|
||||
//! `.Size` for `IDD_CX_CLIENT_CONFIG` — the oracle's `IDD_STRUCTURE_SIZE!`, ported.
|
||||
//!
|
||||
//! The oracle uses a *versioned* size — `IddStructures[INDEX]` when the running framework is OLDER than
|
||||
//! the (1.10) headers we built against (`IddClientVersionHigherThanFramework != 0`). That machinery
|
||||
//! (`IddClientVersionHigherThanFramework` / `IddStructureCount` / `IddStructures`) only exists in the
|
||||
//! iddcx ≥1.4 `IddCxStub`; the WDK on the runner/box links the **1.0** stub (the only `IddCxStub.lib`
|
||||
//! present), which does NOT export those symbols — referencing them is an LNK2019. We target IddCx 1.10
|
||||
//! against a current framework (framework ≥ client ⇒ `higher == false`), where `size_of` is exactly what
|
||||
//! the versioned path returns. So use `size_of` directly. (Revisit the versioned path — with a ≥1.4
|
||||
//! `IddCxStub` linked — only if pre-1.10 Windows must ever be supported, which the punktfunk Windows
|
||||
//! host does not target.)
|
||||
//! IddCx structs are versioned. If the client (our headers) is NEWER than the running framework
|
||||
//! (`IddClientVersionHigherThanFramework != 0`), `size_of` of our struct is too big, so the framework's
|
||||
//! own `IddStructures[INDEX]` size must be used. Otherwise `size_of` is correct. `IddStructures` is null
|
||||
//! until IddCx initialises, so it must ONLY be read in the `higher` branch (the framework populates it
|
||||
//! exactly then). build.rs links the `iddcx>=1.3` stub that exports these symbols. Logged so we can see
|
||||
//! which branch + value the box actually takes.
|
||||
|
||||
use wdk_sys::iddcx;
|
||||
|
||||
/// Correct `.Size` for `IDD_CX_CLIENT_CONFIG` on a framework at least as new as our headers.
|
||||
/// The correct `.Size` for `IDD_CX_CLIENT_CONFIG`, or `None` if the struct is unusable on this framework.
|
||||
#[must_use]
|
||||
pub fn idd_cx_client_config_size() -> Option<u32> {
|
||||
u32::try_from(core::mem::size_of::<iddcx::IDD_CX_CLIENT_CONFIG>()).ok()
|
||||
let local = core::mem::size_of::<iddcx::IDD_CX_CLIENT_CONFIG>();
|
||||
// SAFETY: BOOLEAN static, read-only.
|
||||
let higher = unsafe { (&raw const iddcx::IddClientVersionHigherThanFramework).read() } != 0;
|
||||
dbglog!("[pf-vd] cfg size: higher={higher} size_of={local}");
|
||||
if !higher {
|
||||
return u32::try_from(local).ok();
|
||||
}
|
||||
// SAFETY: read-only; the framework populates the size table exactly when `higher` is true.
|
||||
let count = unsafe { (&raw const iddcx::IddStructureCount).read() };
|
||||
let index = iddcx::_IDDSTRUCTENUM::INDEX_IDD_CX_CLIENT_CONFIG as u32;
|
||||
if index >= count {
|
||||
dbglog!("[pf-vd] cfg size: index {index} >= count {count} -> None");
|
||||
return None;
|
||||
}
|
||||
// SAFETY: `IddStructures` is the framework's size table; `index` validated `< count`.
|
||||
let table = unsafe { (&raw const iddcx::IddStructures).read() };
|
||||
let fw = unsafe { table.add(index as usize).read() };
|
||||
dbglog!("[pf-vd] cfg size: framework={fw}");
|
||||
u32::try_from(fw).ok()
|
||||
}
|
||||
|
||||
/// The framework's expected `.Size` for the `_IDDSTRUCTENUM` struct at `index`, or `None` if the size
|
||||
/// table isn't usable (index out of range / `IddStructures` not yet populated). The framework binds a
|
||||
/// specific IddCx version (the INF's `UmdfExtensions`), which can be OLDER than our headers — newer
|
||||
/// fields (e.g. `IDDCX_ADAPTER_CAPS::StaticDesktopReencodeFrameCount`) make `size_of` too big and
|
||||
/// `IddCxAdapterInitAsync` rejects it; this returns the size the framework actually expects.
|
||||
///
|
||||
/// Only call once the IddCx context is initialised (e.g. from `EvtDeviceD0Entry`, after
|
||||
/// `IddCxDeviceInitialize`) — `IddStructures` may be null before that.
|
||||
#[must_use]
|
||||
pub fn framework_struct_size(index: u32) -> Option<u32> {
|
||||
// SAFETY: read-only.
|
||||
let count = unsafe { (&raw const iddcx::IddStructureCount).read() };
|
||||
if index >= count {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: read-only; `IddStructures` is the framework size table.
|
||||
let table = unsafe { (&raw const iddcx::IddStructures).read() };
|
||||
if table.is_null() {
|
||||
return None;
|
||||
}
|
||||
// SAFETY: `index` validated `< count`; `table` non-null.
|
||||
let size = unsafe { table.add(index as usize).read() };
|
||||
u32::try_from(size).ok()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user