From a4215afa400543f5468e269d7d09f74d05ceac19 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Fri, 13 Nov 2026 14:28:49 -0500 Subject: vgsp: reject beef draw-synth windows whose last colour-target bind is unusable (eng25 correctness guard) The direct-GL lane's draw-synth captures join the verbatim 3D replay lane by numerical run-cover alone, so a non-method data blob whose INC run merely spans the C597 RT block is replayed as state: its last A/B/W/H write per colour target is an unmapped 40-bit VA (c344: RT1 -> 0xff000480a0) and the engine retires with no stores (NOWRITE wrote=0). Gate the beef 'd' admission (single-block and chunk-split) on svc_gl_window_rt_valid(): walk the window with the run grammar, keep the last A/B/W/H write per colour target, and require at least one usable bind (A[7:0]<=1, B<2^30 aligned, 1<=W,H<=0x4000). Validated live (c346, mdev 53dc06b5, ENG26 instrument cycle): 23 bounded '3D mark rejected (beef draw-synth: no valid last colour-target bind)' rows, including the 14865-word 59580-B blob window @off=0x78 and the 542-word 0x4010ed0 twin; the one timing-variant window that does carry a usable RT bind still passed and replayed (wrote=0), and the X lane is unregressed (15x '3D stream marked h=0x1000013' + 'GUEST GR LAUNCH OK' ok=16/17). Refs: CONT.486/487; eng25/eng26 evidence under /tmp/opencode/eng26-*. --- kernel/gsp_sema_service.c | 83 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index e0f1897..4c05935 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -11766,6 +11766,69 @@ static void svc_gl_watch_note(const struct svc_channel *ch, const char *why, svc_gl.blob_len, svc_gl.subch); } +/* + * eng25 (CONT.486): last-write colour-target validity for a beef-family + * draw-synth window. The direct-GL draw captures admitted by the r929/eng24 + * lane can be non-method data whose large INC run happens to cover the + * C597 RT block (c344: window push=0x4010ed0, 7-word SURF prelude then + * 31000201 = INC cnt=0x100 mthd=0x804). That run's last RT writes are + * RT0 A=0x00 B=0x041e0f0c W=0x040f4800 H=0x02027b60 + * RT1 A=0xff B=0x000480a1 W=0x000ea200 H=0x000b7326 -> VA 0xff000480a0 + * i.e. it OVERWRITES the prelude's valid 0x0c000000 bind with an unmapped + * 40-bit VA; the engine then retires the stream with no stores + * (NOWRITE wrote=0). Require at least one target whose LAST A/B/W/H is a + * usable bind before the window is admitted/replayed. The X-lane window + * (RT1 A=0 B=0x15d0000 W=0x780 H=0x438) passes; the c344 beef window fails. + */ +static bool svc_gl_window_rt_valid(const u8 *buf, u32 len, u32 start_off, + u32 at_off) +{ + u32 A[4] = { 0 }, B[4] = { 0 }, W[4] = { 0 }, H[4] = { 0 }; + bool seen[4] = { false }; + u32 o = start_off, j; + + if (!buf || start_off >= at_off || at_off > len) + return false; + while (o + 4u <= at_off) { + u32 h, op, cnt, m, span = 1u, k; + + memcpy(&h, buf + o, 4); + op = (h >> 29) & 7u; + cnt = (h >> 16) & 0xfffu; + m = (h & 0x1fffu) << 2; + if ((op == 1u || op == 3u || op == 5u) && cnt && + o + 4u + cnt * 4u <= at_off) + span = 1u + cnt; + for (k = 0; k < span; k++) { + u32 mm = m + 4u * k, v = 0; + + if (k && op != 1u && op != 3u) + break; + if (k) + memcpy(&v, buf + o + 4u + k * 4u, 4); + else if (op == 4u) + v = (h >> 16) & 0x1fffu; + else + continue; + for (j = 0; j < 4u; j++) { + u32 base = 0x800u + j * 0x40u; + + if (mm == base) { A[j] = v; seen[j] = true; } + else if (mm == base + 4u) { B[j] = v; seen[j] = true; } + else if (mm == base + 8u) { W[j] = v; seen[j] = true; } + else if (mm == base + 0xcu) { H[j] = v; seen[j] = true; } + } + } + o += span * 4u; + } + for (j = 0; j < 4u; j++) + if (seen[j] && (A[j] & ~0xffu) == 0 && (A[j] & 0xffu) <= 1u && + B[j] < 0x40000000u && (B[j] & 3u) == 0 && + W[j] > 0 && W[j] <= 0x4000u && H[j] > 0 && H[j] <= 0x4000u) + return true; + return false; +} + static void svc_gl_flush(struct nv_vgpu_device *vgpu, struct svc_channel *ch, const struct svc_push_state *st, const u8 *buf, @@ -12846,7 +12909,8 @@ static void svc_gl_flush(struct nv_vgpu_device *vgpu, */ if ((op_src[0] == 's' || op_src[0] == 'h' || (op_src[0] == 'd' && - (ch->h_object & 0xfffff000u) == 0xbeef0000u)) && + (ch->h_object & 0xfffff000u) == 0xbeef0000u && + svc_gl_window_rt_valid(buf, len, svc_gl.start_off, at_off))) && svc_gr_cand.valid && len == svc_gr_cand.push_n * 4 && svc_gl.start_off + 8u <= at_off && @@ -12872,7 +12936,22 @@ static void svc_gl_flush(struct nv_vgpu_device *vgpu, * diagnostic below names the failing condition (the next * bound to size). */ - if (len == svc_gr_cand.push_n * 4 && + if (op_src[0] == 'd' && + !svc_gl_window_rt_valid(buf, len, svc_gl.start_off, + at_off)) { + /* eng25: bounded witness when a beef draw-synth + * window is refused - its last colour-target bind + * is not a usable C597 RT (see the clause above). */ + if (svc_gl_mark_log < 64) { + svc_gl_mark_log++; + pr_info("sema-gl: 3D mark rejected (beef draw-synth: no valid last colour-target bind) h=0x%x push=0x%llx win=%u words @off=0x%x\n", + ch->h_object, push_va, + at_off > svc_gl.start_off ? + (at_off - svc_gl.start_off) / 4u : + 0u, + svc_gl.start_off); + } + } else if (len == svc_gr_cand.push_n * 4 && svc_gl.start_off + 8u <= at_off) { svc_gl_stream_chunks(ch, buf, len, at_off); } else if (gsp_sema_dbg && svc_gl_mark_log < 64) { -- cgit v1.2.3