diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 171 |
1 files changed, 170 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 9ba7ed0..96fabcf 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -11907,12 +11907,132 @@ static bool svc_gl_window_state_push(const u8 *buf, u32 len, u32 start_off) return w0 == SVC_FB_STATE_LEAD; } +/* + * eng51 (CONT.512): the RT0-bearing class exemption for the beef draw + * window. The client's direct-GL draw window leads with a REAL + * colour-target bind run (INC cnt=6 at 0x840 binding the client's own + * surface class 0x0a000000/0x0c000000: A fmt<=1, B aligned <1<<30, + * W/H 0x780/0x438) and then continues with a large data region whose + * INC span (hdr 0x3100020x = INC cnt=0x100 mthd=0x804) makes the + * LAST-write heuristic (svc_gl_window_rt_valid) see values of the blob + * class at the RT methods (RT1 A=0xff B=0x000480a1 -> VA 0xff000480a0, + * W/H out of range), so the window was refused before SPH-BIND was ever + * reached (c704-6: `beef draw-synth: no valid last colour-target bind`, + * win=264 words @off=0x4b4). The engine walks the leading bind FIRST, + * so a window whose FIRST write to any target is a usable bind in the + * surface class is a legitimate rt0-bearing replay; windows whose only + * bind is the blob class (eng25 c344 garbage) stay refused. + */ +static bool svc_gl_rt0_class_admit = true; +module_param_named(sema_gl_win_rt0_admit, svc_gl_rt0_class_admit, bool, 0644); +MODULE_PARM_DESC(sema_gl_win_rt0_admit, + "Admit a beef draw-synth window to the verbatim replay lane when its FIRST colour-target write is a usable surface-class bind even if the last-write heuristic refuses it (default 1)"); + +static bool svc_gl_window_rt_first_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 sa[4] = { false }, sb[4] = { false }; + bool sw[4] = { false }, sh[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 && !sa[j]) { + A[j] = v; sa[j] = true; + } else if (mm == base + 4u && !sb[j]) { + B[j] = v; sb[j] = true; + } else if (mm == base + 8u && !sw[j]) { + W[j] = v; sw[j] = true; + } else if (mm == base + 0xcu && !sh[j]) { + H[j] = v; sh[j] = true; + } + } + } + o += span * 4u; + } + for (j = 0; j < 4u; j++) + if (sb[j] && sw[j] && sh[j] && + (A[j] & ~0xffu) == 0 && (A[j] & 0xffu) <= 1u && + B[j] >= 0x08000000u && B[j] < 0x40000000u && + (B[j] & 3u) == 0 && W[j] > 0 && W[j] <= 0x4000u && + H[j] > 0 && H[j] <= 0x4000u) + return true; + /* + * eng51: bounded miss witness. The c710-7 refusals were a 375-word + * window class (@off=0x640, push 0x40ef9d8/0x410f9d8) whose + * first-valid groups did not match the exemption; name the bytes + * and the groups so the next miss is one grep away. + */ + { + static u32 rt0_miss_log; + u32 w0 = 0, w1 = 0, w2 = 0, w3 = 0; + + if (gsp_sema_dbg && rt0_miss_log < 8u) { + rt0_miss_log++; + if (start_off + 16u <= at_off) { + memcpy(&w0, buf + start_off, 4); + memcpy(&w1, buf + start_off + 4, 4); + memcpy(&w2, buf + start_off + 8, 4); + memcpy(&w3, buf + start_off + 12, 4); + } + pr_info("sema-gl: RT0-FIRST-MISS start=0x%x at=0x%x w0..3=%08x %08x %08x %08x groups A=%08x,%08x,%08x,%08x B=%08x,%08x,%08x,%08x W=%08x,%08x,%08x,%08x H=%08x,%08x,%08x,%08x seen=%d%d%d%d/%d%d%d%d\n", + start_off, at_off, w0, w1, w2, w3, + A[0], A[1], A[2], A[3], + B[0], B[1], B[2], B[3], + W[0], W[1], W[2], W[3], + H[0], H[1], H[2], H[3], + sa[0], sa[1], sa[2], sa[3], + sb[0], sb[1], sb[2], sb[3]); + } + } + return false; +} + static bool svc_gl_window_drawwin_ok(const u8 *buf, u32 len, u32 start_off, u32 at_off) { if (svc_gl_window_state_push(buf, len, start_off)) return true; - return svc_gl_window_rt_valid(buf, len, start_off, at_off); + if (svc_gl_window_rt_valid(buf, len, start_off, at_off)) + return true; + if (READ_ONCE(svc_gl_rt0_class_admit) && + svc_gl_window_rt_first_valid(buf, len, start_off, at_off)) { + static u32 rt0_adm_log; + + if (rt0_adm_log < 16u) { + rt0_adm_log++; + pr_info("sema-gl: 3D mark admitted (RT0-bearing class: first-bind valid, last-write refused) start=0x%x at=0x%x win=%u words\n", + start_off, at_off, + at_off > start_off ? (at_off - start_off) / 4u : 0u); + } + return true; + } + return false; } static void svc_gl_flush(struct nv_vgpu_device *vgpu, @@ -19892,6 +20012,18 @@ static u64 svc_init_cap_va; static bool svc_init_cap_done; static u32 svc_lmem_hits; static u32 svc_lmem_seen; +/* + * eng51 (CONT.512): the LAST large beef push of the boot. The init push is + * the channel-init/setup stream; the direct-GL draw arrives in a later push + * (c714: 0x4250110, 6400 B) that is transient in guest RAM. Preserve it so + * the RT bind / draw methods can be decoded offline after the guest has + * recycled the pushbuffer (gsp-phys-last-push). + */ +static u8 svc_last_cap[SVC_INIT_CAP_BYTES]; +static u32 svc_last_cap_len; +static u32 svc_last_cap_h; +static u64 svc_last_cap_va; +static bool svc_last_cap_done; static void svc_mme_prelude_capture(const u8 *buf, u32 len, u64 push_va, u32 h_object); @@ -19966,6 +20098,24 @@ static void svc_init_push_scan(const u8 *buf, u32 len, u64 push_va, u32 h_object h_object, mn, mg, an, ag); } } + /* + * eng51 (CONT.512): keep the most recent large beef push too. The + * init capture above is one-shot (the channel-init stream); the + * direct-GL draw push arrives later and is the window the RT/draw + * admission must decode. Copy is bounded (64 KiB) and only for + * beef-family pushes that carry a non-zero head. 256 B (not 4 KiB): + * c716's direct-GL draw pushes are 2252/324 B, so the 4 KiB floor + * preserved only the 59 KB setup push. + */ + if ((h_object & 0xfffff000u) == 0xbeef0000u && + len >= 256u && len <= SVC_INIT_CAP_BYTES && + memchr_inv(buf, 0, min_t(u32, len, 64u))) { + svc_last_cap_len = len; + memcpy(svc_last_cap, buf, len); + svc_last_cap_h = h_object; + svc_last_cap_va = push_va; + svc_last_cap_done = true; + } } const u8 *gsp_sema_init_cap_get(u32 *len, u32 *h, u64 *va, u32 *lmem_seen) @@ -19977,6 +20127,14 @@ const u8 *gsp_sema_init_cap_get(u32 *len, u32 *h, u64 *va, u32 *lmem_seen) return svc_init_cap; } +const u8 *gsp_sema_last_cap_get(u32 *len, u32 *h, u64 *va) +{ + *len = svc_last_cap_len; + *h = svc_last_cap_h; + *va = svc_last_cap_va; + return svc_last_cap; +} + /* * SESSION 153-CONTINUED-53: MME context-setup prelude buffer. * @@ -31123,6 +31281,17 @@ static bool svc_gr_ram_ring_scan(struct nv_vgpu_device *vgpu, u64 chunk = min_t(u64, SVC_SCAN_CHUNK, end - gpa); u32 o; + /* + * eng51 (CONT.512): the linear scan walks the guest's + * non-RAM windows too (legacy VGA/BIOS below 1 MiB and the + * sub-4-GiB PCI hole). Every 64 KiB read there fails, and + * the per-GPA witness used to emit ~32k lines per sweep, + * rotating dmesg and hiding the draw-capture evidence. + * Those windows can never hold the ring; skip them. + */ + if ((gpa >= 0xa0000ULL && gpa < 0x100000ULL) || + (gpa >= 0x80000000ULL && gpa < 0x100000000ULL)) + continue; if (svc_read(vgpu, gpa, buf, chunk)) { if (gsp_sema_dbg && (ch->h_object & 0xfffff000u) == 0xbeef0000u) { |
