# DF-4198 — get_bytes_per_element() returns 0 for dm_444_8/dm_mono_8 and unhandled formats → integer divide-by-zero (#DE) in get_surf_rq_param + dml_log2(0)=-127 UB-shift family

File under audit: `sys/dev/drm/amd/display/dc/dml/dml1_display_rq_dlg_calc.c` (pass 2)

## What

`get_bytes_per_element()` (dml1_display_rq_dlg_calc.c:40-65) handles only
dm_444_16/32/64 and dm_420_8/10. The legal enum value
`dm_444_8` (= `dm_mono_8`, display_mode_enums.h:42-43) — and *any* out-of-set
enum — yields `ret_val = 0`. With bytes_per_element == 0 the file then:

* **live #DE**: `get_surf_rq_param()` line 641, linear surfaces:
  `blk256_width = 256 / bytes_per_element;` → integer division by zero →
  kernel #DE → panic (SIGFPE in the model harness).
* **dead-code #DE** (source-level): line 745
  `meta_blk_width = meta_blk_bytes * 256 / bytes_per_element / meta_blk_height;`
  — `meta_blk_width` is never read, so gcc -O2 eliminates it (harness
  confirmed: tiled mono8 does NOT trap), but the source division is still
  against the same zero.
* **UB shift family**: `dml_log2(0)` returns **-127** (dcn_bw_log bit-trick,
  calcs/dcn_calc_math.c:112-126: log2f-mantissa approximation of 0.0 gives
  -127), so every downstream `1 << log2_*` / `>> log2_*`
  (lines 636/652-653/678/684/708-709/719/736-739/739) and
  `log2_xxx` arithmetic gets -127-based garbage; even non-linear mono8
  silently programs wrong RQ/DLG registers (harness: sw=1919 h=2,
  stored_swath=0 — nonsense for a 1-byte format).

## Reachability (honest)

The only in-tree caller of `dml1_rq_dlg_get_rq_params` is
`dcn_bw_calc_rq_dlg_ttu()` (calcs/dcn_calcs.c:487), and its format mapping
(calcs/dcn_calcs.c:353-377) maps VIDEO_420→dm_420_8/10,
ARGB16161616*→dm_444_64, **everything else→dm_444_32** — it never produces
dm_444_8 today. The defect is therefore *latent*: one new format mapping
(or a DCN1 caller passing dm_mono_8, which the enum explicitly defines as an
alias) turns it into a kernel panic on modeset validation. Additionally all
of it sits behind DCN1 (Raven) hardware. Arithmetic certainty, trigger
currently absent — hence Low severity.

## How it is proven here

`dml1_harness.c` compiles the REAL, unmodified
`dml1_display_rq_dlg_calc.c` (plus real `dcn_calc_math.c`,
`dml_common_defs.c`, real headers; only `dm_services.h` is a stub providing
the non-fatal WARN_ON-style ASSERT, matching os_types.h:76 release semantics)
on the DragonFly guest and drives it with a realistic DCN1 config
(1920x1080, det_buffer 164 KB, vmm_page 4096):

```
$ ./dml1_harness normal        # dm_444_32 (what dcn_calcs maps) — OK, sane regs
$ ./dml1_harness mono8         # dm_444_8, tiled — NO trap (line 745 is dead
                               #   code at -O2) but silently WRONG values
$ ./dml1_harness mono8_linear  # dm_444_8 + dm_sw_linear — SIGFPE at :641
Floating point exception (core dumped)   rc=136   (3/3 runs)
```

`dml1_harness_fixed` is the SAME harness compiled with `fix.diff` applied to
the real dml1 file: all three modes complete rc=0 and mono8 now produces
sane values (bpe=1).

## Reproduce

```
./build.sh          # copies the real files from /usr/src, builds baseline+fixed
./run.sh            # baseline mono8_linear -> SIGFPE; fixed -> clean
```

## Fix

`fix.diff`: (1) handle `dm_444_8` → 1 byte/element in
get_bytes_per_element (mono 8bpc is 1 byte per element, matching the enum
alias); (2) defense-in-depth: bail out of get_surf_rq_param when
bytes_per_element == 0 (ASSERT is only WARN_ON in release builds, so the
explicit return is what prevents the fault).
