# DF-4493 — rs780_dpm.c: NULL boot_ps / skipped state parse → NULL-deref page-fault panic

## What

Two ways to reach a NULL `rdev->pm.dpm.boot_ps` (or NULL `ps_priv`) that the
DPM enable path dereferences without any check:

1. **No BOOT-classified state** (rs780_dpm.c:741-742 sets `boot_ps` only
   when `rps->class & ATOM_PPLIB_CLASSIFICATION_BOOT`). A PowerPlayInfo
   table whose non-clock infos lack the BOOT bit parses "successfully"
   (`rs780_parse_power_table()` returns 0, :843), leaving `boot_ps == NULL`.
   `radeon_pm_init_dpm()` (radeon_pm.c:1448) **discards** the dpm_init
   return, sets `current_ps = requested_ps = boot_ps` (:1449) and calls
   `radeon_dpm_enable()` (:1453) → `rs780_dpm_enable()` fetches `boot_ps`
   (:600) and passes it to `rs780_initialize_dpm_parameters()` (:608) →
   `rs780_initialize_dpm_power_state()` does
   `default_state = rs780_get_ps(boot_ps)` (:78) → **NULL->ps_priv read at
   address 0x28** → page-fault panic.

2. **`ucStateEntrySize == 1`**: the guard
   `if (power_info->pplib.ucStateEntrySize - 1)` (:822) is false, so NO
   state is parsed at all — every `ps[i].ps_priv` stays NULL and `boot_ps`
   is never set — yet `num_ps = ucNumStates` is still assigned (:842) and
   the function returns success. Any later `rs780_get_ps()` consumer
   derefs NULL: `rs780_dpm_print_power_state()` (:946 `ps->sclk_low`,
   address 0x8), `rs780_dpm_set_power_state()` (:567-568),
   `rs780_dpm_get_sclk()` (:965-970), `rs780_dpm_force_performance_level()`
   (:1031).

Family: DF-4187 (sumo), DF-4124 (rv6xx), DF-4143 (trinity), DF-4118
(cypress) — rs780 is the last sibling with the same shape.

## Reproduce

```
./build.sh
./run.sh            # modes 4493 (no BOOT state) and 4493b (ucStateEntrySize==1)
```

Expected baseline (run.log):

* mode 4493: `boot_ps=0x0` then `*** SIGNAL 11 at address 0x28 ***`, exit=99
* mode 4493b: `ps[0].ps_priv=0x0` then `*** SIGNAL 11 at address 0x8 ***`, exit=99

Expected with `harness_fixed`: mode 4493 prints
`DRM_ERROR: no boot power state, refusing to enable DPM` (enable guard),
mode 4493b rejects the table at parse (`invalid state entry size 1`),
both exit=0.

Kernel-level reproduction is hardware-gated (no RS780 IGP in the QEMU
guest); the harness is a verbatim replica — see VERDICT.md.

## Fix

`fix.diff` (in this directory): `rs780_dpm_enable()` refuses to run without
a boot power state, and the parse rejects `ucStateEntrySize < 2` (an
ATOM_PPLIB_STATE is 2 bytes). Validated: `radeon.ko` builds under `-Werror`
after applying the fix to the guest's `/usr/src` (radeon_module_build.log,
MAKE_RC=0).
