# DF-4999 — VERDICT

**Finding**: prototype/definition parameter-order mismatch for
`generic_reg_wait` between `dm_services.h:152-156` and `dc_helper.c:254-257`.

## Status: untested (static; the audit guest has no DRM/DC device — `/dev/dri` absent, same as the DF-4435 verification)

## Proof

1. Declaration (header every DC translation unit includes):

   ```c
   /* sys/dev/drm/amd/display/dc/dm_services.h:152 */
   unsigned int generic_reg_wait(const struct dc_context *ctx,
   	uint32_t addr, uint32_t mask, uint32_t shift, uint32_t condition_value,
   	unsigned int delay_between_poll_us, unsigned int time_out_num_tries,
   	const char *func_name, int line);
   ```

2. Definition (this file):

   ```c
   /* sys/dev/drm/amd/display/dc/dc_helper.c:254 */
   uint32_t generic_reg_wait(const struct dc_context *ctx,
   	uint32_t addr, uint32_t shift, uint32_t mask, uint32_t condition_value,
   	unsigned int delay_between_poll_us, unsigned int time_out_num_tries,
   	const char *func_name, int line)
   ```

3. Harmless today *only* because C binds arguments positionally over
   identical `uint32_t` types and the sole call family is the `REG_WAIT`
   macro (`inc/reg_helper.h:245-248`), whose `FN()` expansion orders
   **shift, mask** — matching the definition, contradicting the header.
   Direct-call census: `rg generic_reg_wait\(` over
   `sys/dev/drm/amd/display/dc` returns only the definition, the header
   declaration, and the `REG_WAIT` macro — no other call sites.

4. The trap for future callers is concrete: a header-believing caller
   transposes the pair; `get_reg_field_value_ex(reg_val, mask, shift)`
   (dm_services.h:112-116) computes `(mask & reg_val) >> shift` with the
   roles swapped → condition never satisfied → full poll budget burned
   (in-tree budgets up to 100 ms, e.g. dcn10_optc.c:496) → `dm_error`
   timeout + `BREAK_TO_DEBUGGER()` (dc_helper.c:288-293) on every call —
   and for the sibling varargs family (`generic_reg_update_ex`) an
   equivalent declaration/consumer disagreement *would* feed stack garbage
   into MMIO writes (va_arg walks past the supplied triplets), which is why
   the header contract matters even where the runtime effect today is nil.
   AMD's own code comment (dc_helper.c:223-225) acknowledges the varargs
   family is "prone to stack corruption type of bugs".

## Fix

One-line header correction (fix.diff) making the declaration identical to
the definition (also unifying the return type to `uint32_t`).  No behavior
change for existing callers.

## Fix validation

`patch --dry-run` OK.  No kernel build possible on the guest (DC requires
AMD display hardware; guest has no DRM device), but the edit is
declaration-only — it cannot change codegen of the existing macro callers.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
