diff --git a/.gitea/workflows/windows-drivers.yml b/.gitea/workflows/windows-drivers.yml index 1c5bbee..db1e42f 100644 --- a/.gitea/workflows/windows-drivers.yml +++ b/.gitea/workflows/windows-drivers.yml @@ -129,39 +129,22 @@ jobs: # separate provision run on the single runner. Path is relative to the job working-directory # (packaging/windows/drivers). Near-noop once the toolchain is present. run: ../../../scripts/ci/provision-windows-wdk.ps1 - - name: cargo build wdk-probe (windows-drivers-rs) - run: cargo build -p wdk-probe -v - - name: Dump generated iddcx.rs structure (diagnostic — runs even on build failure) - if: always() - run: | - $gen = Get-ChildItem -Recurse target -Filter iddcx.rs -ErrorAction SilentlyContinue | - Where-Object { $_.FullName -match 'out\\iddcx.rs$' } | Select-Object -First 1 - if (-not $gen) { Write-Host "no generated iddcx.rs found"; exit 0 } - Write-Host "generated: $($gen.FullName)" - $L = Get-Content $gen.FullName - Write-Host "total lines: $($L.Count)" - Write-Host "--- head (1-6) ---"; for ($i=0; $i -lt 6 -and $i -lt $L.Count; $i++) { Write-Host ("{0}: {1}" -f ($i+1), $L[$i]) } - Write-Host "--- 'mod ' / 'pub mod ' lines ---" - Select-String -Path $gen.FullName -Pattern '^\s*(pub )?mod ' | Select-Object -First 12 | ForEach-Object { Write-Host ("{0}: {1}" -f $_.LineNumber, $_.Line.Trim()) } - Write-Host "--- first 4 lines containing UINT (with context module) ---" - Select-String -Path $gen.FullName -Pattern '\bUINT\b' | Select-Object -First 4 | ForEach-Object { - $n = $_.LineNumber - Write-Host ("L{0}: {1}" -f $n, $_.Line.Trim()) - } - Write-Host "--- context around first UINT use ---" - $first = (Select-String -Path $gen.FullName -Pattern '\bUINT\b' | Select-Object -First 1).LineNumber - if ($first) { for ($i=[Math]::Max(0,$first-6); $i -lt $first+2 -and $i -lt $L.Count; $i++) { Write-Host ("{0}: {1}" -f ($i+1), $L[$i]) } } + - name: cargo build the driver workspace (wdk-probe + wdk-iddcx + pf-vdisplay) + # Whole workspace: wdk-probe (toolchain/surface-assert probe) + wdk-iddcx (DDI wrappers) + + # pf-vdisplay (the real IddCx driver). pf-vdisplay linking proves the IddCx call sites resolve + # against IddCxStub end-to-end (M1 step 2 gate). + run: cargo build -v - name: Inspect /INTEGRITYCHECK (before) — expect FORCE_INTEGRITY set by wdk-build run: | # explicit --target (.cargo/config.toml) -> output under the triple subdir. - $dll = "target\x86_64-pc-windows-msvc\debug\wdk_probe.dll" - if (-not (Test-Path $dll)) { throw "wdk_probe.dll not produced at $dll" } + $dll = "target\x86_64-pc-windows-msvc\debug\pf_vdisplay.dll" + if (-not (Test-Path $dll)) { throw "pf_vdisplay.dll not produced at $dll" } $b = [IO.File]::ReadAllBytes($dll) $pe = [BitConverter]::ToInt32($b, 0x3c) $dllchar = [BitConverter]::ToUInt16($b, $pe + 0x5e) # OptionalHeader.DllCharacteristics - Write-Host ("wdk_probe.dll built OK ({0:N0} bytes)" -f (Get-Item $dll).Length) + Write-Host ("pf_vdisplay.dll built OK ({0:N0} bytes)" -f (Get-Item $dll).Length) Write-Host ("BEFORE: DllCharacteristics = 0x{0:X4}; FORCE_INTEGRITY = {1}" -f $dllchar, (($dllchar -band 0x0080) -ne 0)) - name: Clear FORCE_INTEGRITY (self-signed-load fix) + verify # wdk-build sets /INTEGRITYCHECK unconditionally -> a self-signed driver won't load. Clear the PE # bit deterministically (the reusable packaging step; signing/.cat happen later for real drivers). - run: ../clear-force-integrity.ps1 -Path target\x86_64-pc-windows-msvc\debug\wdk_probe.dll + run: ../clear-force-integrity.ps1 -Path target\x86_64-pc-windows-msvc\debug\pf_vdisplay.dll diff --git a/packaging/windows/drivers/pf-vdisplay/src/lib.rs b/packaging/windows/drivers/pf-vdisplay/src/lib.rs index 260d33e..b0e1e6a 100644 --- a/packaging/windows/drivers/pf-vdisplay/src/lib.rs +++ b/packaging/windows/drivers/pf-vdisplay/src/lib.rs @@ -11,6 +11,7 @@ #![allow(non_snake_case, clippy::missing_safety_doc)] mod callbacks; +#[allow(dead_code)] // salvaged verbatim; wired into the mode callbacks in STEP 4 mod edid; mod entry; mod size; diff --git a/packaging/windows/drivers/pf-vdisplay/src/size.rs b/packaging/windows/drivers/pf-vdisplay/src/size.rs index 70069fb..2cf126e 100644 --- a/packaging/windows/drivers/pf-vdisplay/src/size.rs +++ b/packaging/windows/drivers/pf-vdisplay/src/size.rs @@ -1,30 +1,19 @@ -//! Versioned IddCx struct sizing — the oracle's `IDD_STRUCTURE_SIZE!` ported to wdk-sys. +//! `.Size` for `IDD_CX_CLIENT_CONFIG`. //! -//! IddCx structs are versioned: if the running framework is OLDER than the (1.10) headers we built -//! against, our locally-compiled struct may be LARGER than the framework understands, so `.Size` must -//! come from the framework's own size table (`IddStructures[INDEX_]`), not `size_of`. `None` -//! means the struct is unusable on this framework. When the framework is at least our version, -//! `size_of` is correct. (wdk-sys uses ModuleConsts: `_IDDSTRUCTENUM::INDEX_*`, not the oracle's -//! NewType `.0`.) +//! 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.) use wdk_sys::iddcx; -/// Correct `.Size` for `IDD_CX_CLIENT_CONFIG`, or `None` if it can't be used on this framework. +/// Correct `.Size` for `IDD_CX_CLIENT_CONFIG` on a framework at least as new as our headers. #[must_use] pub fn idd_cx_client_config_size() -> Option { - // SAFETY: read-only access to the stub-provided framework globals. - let higher = unsafe { (&raw const iddcx::IddClientVersionHigherThanFramework).read() } != 0; - if !higher { - return u32::try_from(core::mem::size_of::()).ok(); - } - // SAFETY: read-only. - let count = unsafe { (&raw const iddcx::IddStructureCount).read() }; - let index = iddcx::_IDDSTRUCTENUM::INDEX_IDD_CX_CLIENT_CONFIG as u32; - if index >= count { - return None; // struct cannot be used on this (older) framework - } - // SAFETY: `IddStructures` is the framework's size table; `index` is validated `< count`. - let table = unsafe { (&raw const iddcx::IddStructures).read() }; - let size = unsafe { table.add(index as usize).read() }; - u32::try_from(size).ok() + u32::try_from(core::mem::size_of::()).ok() }