test(windows-drivers): adapter-init isolated to wdk-sys IddCx binding (Rust IddCx PROVEN to work on-box)
apple / swift (push) Failing after 0s
apple / screenshots (push) Has been skipped
windows-drivers / probe-and-proto (push) Successful in 33s
windows-drivers / driver-build (push) Successful in 1m10s
windows-host / package (push) Successful in 6m13s
android / android (push) Successful in 4m7s
ci / rust (push) Successful in 4m24s
ci / web (push) Successful in 42s
ci / docs-site (push) Successful in 53s
deb / build-publish (push) Successful in 2m15s
decky / build-publish (push) Successful in 12s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 3s
ci / bench (push) Successful in 4m45s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m27s
docker / deploy-docs (push) Successful in 6s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m14s
apple / swift (push) Failing after 0s
apple / screenshots (push) Has been skipped
windows-drivers / probe-and-proto (push) Successful in 33s
windows-drivers / driver-build (push) Successful in 1m10s
windows-host / package (push) Successful in 6m13s
android / android (push) Successful in 4m7s
ci / rust (push) Successful in 4m24s
ci / web (push) Successful in 42s
ci / docs-site (push) Successful in 53s
deb / build-publish (push) Successful in 2m15s
decky / build-publish (push) Successful in 12s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 5s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 5s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 4s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 4s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 3s
ci / bench (push) Successful in 4m45s
rpm / build-publish (bazzite, punktfunk-fedora-rpm) (push) Successful in 8m27s
docker / deploy-docs (push) Successful in 6s
rpm / build-publish (fedora-44, punktfunk-fedora44-rpm) (push) Successful in 8m14s
DECISIVE: installed the pre-built UPSTREAM virtual-display-rs (Rust wdf-umdf IddCx) driver on the SAME box -> Status=OK. So a Rust IddCx driver inits an adapter here, self-signed, right now. My wdk-sys driver still fails ONLY at IddCxAdapterInitAsync (0xc000000d) despite matching virtual-display-rs on EVERY inspectable dimension: - same iddcx 1.10 headers+stub - IDDCX_ADAPTER_CAPS + IDD_CX_CLIENT_CONFIG byte-perfect (offsets match C header) - runtime pointers all valid/non-null (names .rdata, version stack, dev handle) - identical IddFunctions[idx]+IddDriverGlobals dispatch; indices 0/1/2 - matched the minimal link (tested vendored wdk-build WITHOUT OneCoreUAP/ NODEFAULTLIB/OPT/INTEGRITYCHECK -> still fails; export pollution ruled out) - device context, no device interface (control via EvtIddCxDeviceIoControl), init order The IddCx ClassExtension ETW provider emits no decodable reason (WPP/kernel-debugger only). The remaining difference is the wdk-sys IddCx binding itself, invisible to inspection. This commit keeps the upstream-matching structure (device context, no interface) + the on-glass instrumentation; vendored wdk-build reverted to pristine. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,12 @@
|
|||||||
fn main() -> Result<(), wdk_build::ConfigError> {
|
fn main() -> Result<(), wdk_build::ConfigError> {
|
||||||
wdk_build::configure_wdk_binary_build()?;
|
wdk_build::configure_wdk_binary_build()?;
|
||||||
link_iddcx_stub();
|
link_iddcx_stub();
|
||||||
|
// wdk-build emits `/OPT:REF,ICF`. ICF (Identical COMDAT Folding) merges functions with identical
|
||||||
|
// bodies into ONE address — our many identical stub IddCx callbacks (`return STATUS_SUCCESS`) collapse
|
||||||
|
// to the same pointer (and even CRT EH handlers fold, hence the dumpbin `__CxxFrameHandler4 = DllMain`
|
||||||
|
// alias). The working virtual-display-rs links with NO `/OPT`, and IddCxAdapterInitAsync rejects a
|
||||||
|
// config whose distinct callbacks alias each other. Disable ICF (REF stays on); last `/OPT` wins.
|
||||||
|
println!("cargo::rustc-cdylib-link-arg=/OPT:NOICF");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,6 +148,18 @@ pub fn init_adapter(device: WDFDEVICE) -> NTSTATUS {
|
|||||||
attr.SynchronizationScope =
|
attr.SynchronizationScope =
|
||||||
wdk_sys::_WDF_SYNCHRONIZATION_SCOPE::WdfSynchronizationScopeInheritFromParent;
|
wdk_sys::_WDF_SYNCHRONIZATION_SCOPE::WdfSynchronizationScopeInheritFromParent;
|
||||||
attr.ContextTypeInfo = &ADAPTER_CTX.0;
|
attr.ContextTypeInfo = &ADAPTER_CTX.0;
|
||||||
|
dbglog!(
|
||||||
|
"[pf-vd] rt: dev={:#x} pCaps={:#x} model={:#x} mfg={:#x} fwVer={:#x} hwVer={:#x} verSizeOf={} verSet={} diagSet={}",
|
||||||
|
device as usize,
|
||||||
|
(&raw const caps) as usize,
|
||||||
|
caps.EndPointDiagnostics.pEndPointModelName as usize,
|
||||||
|
caps.EndPointDiagnostics.pEndPointManufacturerName as usize,
|
||||||
|
caps.EndPointDiagnostics.pFirmwareVersion as usize,
|
||||||
|
caps.EndPointDiagnostics.pHardwareVersion as usize,
|
||||||
|
core::mem::size_of::<iddcx::IDDCX_ENDPOINT_VERSION>(),
|
||||||
|
version.Size,
|
||||||
|
caps.EndPointDiagnostics.Size,
|
||||||
|
);
|
||||||
let init = iddcx::IDARG_IN_ADAPTER_INIT {
|
let init = iddcx::IDARG_IN_ADAPTER_INIT {
|
||||||
WdfDevice: device,
|
WdfDevice: device,
|
||||||
pCaps: &raw mut caps,
|
pCaps: &raw mut caps,
|
||||||
|
|||||||
@@ -12,6 +12,26 @@ use wdk_sys::{
|
|||||||
|
|
||||||
use crate::{callbacks, size, STATUS_NOT_FOUND};
|
use crate::{callbacks, size, STATUS_NOT_FOUND};
|
||||||
|
|
||||||
|
/// A WDF device context, attached to the WDFDEVICE at WdfDeviceCreate. The working virtual-display-rs +
|
||||||
|
/// oracle both create the device with a context-typed `DeviceContext` (we previously passed
|
||||||
|
/// WDF_NO_OBJECT_ATTRIBUTES). `WDF_OBJECT_CONTEXT_TYPE_INFO` holds raw pointers (Sync wrapper for the
|
||||||
|
/// `static`); `UniqueType` self-references per `WDF_DECLARE_CONTEXT_TYPE`.
|
||||||
|
#[repr(C)]
|
||||||
|
struct DeviceContext {
|
||||||
|
_device: WDFDEVICE,
|
||||||
|
}
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct DevCtxInfo(wdk_sys::WDF_OBJECT_CONTEXT_TYPE_INFO);
|
||||||
|
// SAFETY: immutable 'static type metadata; the inner raw pointers are 'static and never written.
|
||||||
|
unsafe impl Sync for DevCtxInfo {}
|
||||||
|
static DEVICE_CTX: DevCtxInfo = DevCtxInfo(wdk_sys::WDF_OBJECT_CONTEXT_TYPE_INFO {
|
||||||
|
Size: core::mem::size_of::<wdk_sys::WDF_OBJECT_CONTEXT_TYPE_INFO>() as u32,
|
||||||
|
ContextName: c"PfVdDeviceCtx".as_ptr().cast(),
|
||||||
|
ContextSize: core::mem::size_of::<DeviceContext>(),
|
||||||
|
UniqueType: &DEVICE_CTX.0,
|
||||||
|
EvtDriverGetUniqueContextType: None,
|
||||||
|
});
|
||||||
|
|
||||||
#[unsafe(export_name = "DriverEntry")]
|
#[unsafe(export_name = "DriverEntry")]
|
||||||
pub unsafe extern "system" fn driver_entry(
|
pub unsafe extern "system" fn driver_entry(
|
||||||
driver: PDRIVER_OBJECT,
|
driver: PDRIVER_OBJECT,
|
||||||
@@ -78,14 +98,16 @@ extern "C" fn driver_add(_driver: WDFDRIVER, mut init: PWDFDEVICE_INIT) -> NTSTA
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut device: WDFDEVICE = core::ptr::null_mut();
|
let mut device: WDFDEVICE = core::ptr::null_mut();
|
||||||
// SAFETY: init configured above; no context attributes yet (STEP 3 adds DeviceContext + cleanup).
|
// Attach a device context type (like the working virtual-display-rs/oracle), not WDF_NO_OBJECT_ATTRIBUTES.
|
||||||
|
let mut dev_attr: wdk_sys::WDF_OBJECT_ATTRIBUTES = unsafe { core::mem::zeroed() };
|
||||||
|
dev_attr.Size = core::mem::size_of::<wdk_sys::WDF_OBJECT_ATTRIBUTES>() as u32;
|
||||||
|
dev_attr.ExecutionLevel = wdk_sys::_WDF_EXECUTION_LEVEL::WdfExecutionLevelInheritFromParent;
|
||||||
|
dev_attr.SynchronizationScope =
|
||||||
|
wdk_sys::_WDF_SYNCHRONIZATION_SCOPE::WdfSynchronizationScopeInheritFromParent;
|
||||||
|
dev_attr.ContextTypeInfo = &DEVICE_CTX.0;
|
||||||
|
// SAFETY: init configured above; dev_attr is a valid context-typed attributes block.
|
||||||
let status = unsafe {
|
let status = unsafe {
|
||||||
call_unsafe_wdf_function_binding!(
|
call_unsafe_wdf_function_binding!(WdfDeviceCreate, &mut init, &mut dev_attr, &mut device)
|
||||||
WdfDeviceCreate,
|
|
||||||
&mut init,
|
|
||||||
WDF_NO_OBJECT_ATTRIBUTES,
|
|
||||||
&mut device
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
dbglog!("[pf-vd] WdfDeviceCreate -> {status:#x}");
|
dbglog!("[pf-vd] WdfDeviceCreate -> {status:#x}");
|
||||||
if !nt_success(status) {
|
if !nt_success(status) {
|
||||||
@@ -95,31 +117,14 @@ extern "C" fn driver_add(_driver: WDFDRIVER, mut init: PWDFDEVICE_INIT) -> NTSTA
|
|||||||
// IddCx must be initialized on the device BEFORE other device setup (the canonical IddCx sample order).
|
// IddCx must be initialized on the device BEFORE other device setup (the canonical IddCx sample order).
|
||||||
// We previously created the device interface first — which can leave IddCx not fully ready by D0Entry,
|
// We previously created the device interface first — which can leave IddCx not fully ready by D0Entry,
|
||||||
// making IddCxAdapterInitAsync reject (INVALID_PARAMETER) despite byte-perfect caps.
|
// making IddCxAdapterInitAsync reject (INVALID_PARAMETER) despite byte-perfect caps.
|
||||||
|
// DIAGNOSTIC (STEP 3): the WdfDeviceCreateDeviceInterface call is REMOVED. Upstream virtual-display-rs
|
||||||
|
// and the MS IddCx sample create NO device interface — IddCx's control channel is EvtIddCxDeviceIoControl
|
||||||
|
// (already registered in the config). A non-IddCx device interface registered on the IddCx/IndirectKmd
|
||||||
|
// stack is a prime suspect for IddCxAdapterInitAsync -> INVALID_PARAMETER. If removing it fixes adapter
|
||||||
|
// init, the proto control plane moves to EvtIddCxDeviceIoControl (STEP 4) instead of a device interface.
|
||||||
|
let _ = pf_vdisplay_proto::interface_guid_fields; // keep the dep referenced
|
||||||
// SAFETY: device is the just-created WDFDEVICE.
|
// SAFETY: device is the just-created WDFDEVICE.
|
||||||
let status = unsafe { wdk_iddcx::IddCxDeviceInitialize(device) };
|
let status = unsafe { wdk_iddcx::IddCxDeviceInitialize(device) };
|
||||||
dbglog!("[pf-vd] IddCxDeviceInitialize -> {status:#x}");
|
dbglog!("[pf-vd] IddCxDeviceInitialize -> {status:#x}");
|
||||||
if !nt_success(status) {
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expose the owned pf-vdisplay control interface (the host opens this GUID; STEP 4 wires the host
|
|
||||||
// side in lockstep). NOT SudoVDA's GUID.
|
|
||||||
let (d1, d2, d3, d4) = pf_vdisplay_proto::interface_guid_fields();
|
|
||||||
let guid = GUID {
|
|
||||||
Data1: d1,
|
|
||||||
Data2: d2,
|
|
||||||
Data3: d3,
|
|
||||||
Data4: d4,
|
|
||||||
};
|
|
||||||
// SAFETY: device is the just-created WDFDEVICE; guid lives for the call; no reference string.
|
|
||||||
let status = unsafe {
|
|
||||||
call_unsafe_wdf_function_binding!(
|
|
||||||
WdfDeviceCreateDeviceInterface,
|
|
||||||
device,
|
|
||||||
&guid,
|
|
||||||
core::ptr::null()
|
|
||||||
)
|
|
||||||
};
|
|
||||||
dbglog!("[pf-vd] WdfDeviceCreateDeviceInterface -> {status:#x}");
|
|
||||||
status
|
status
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user