summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c103
1 files changed, 101 insertions, 2 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 42fcdb1..eba0305 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -19900,6 +19900,30 @@ module_param_named(sema_gl_mme_reloc, gsp_phys_rmcall_gr_mme_reloc, bool, 0644);
MODULE_PARM_DESC(sema_gl_mme_reloc,
"Relocate CALL_MME_MACRO/DATA(j) run payload words whose page resolves in the launch page set to shadow VAs in 3D replays (default 0 = off)");
+/*
+ * SESSION 153-CONTINUED-58: torn-read zero guard for the vertex-attribute
+ * families. The r1098/r1099 first-launch class error
+ * (`Class Error: ChId 0001, Class 0000c597, Offset 00001168,
+ * Data 00000000, ErrorCode 00000005` = SET_VERTEX_ATTRIBUTE_A(2) written
+ * with NUMERICAL_TYPE=0, the header's UNUSED_ENUM_DO_NOT_USE value ->
+ * INVALID_ENUM) is written by a replayed window run
+ * `20030458 38400000 38200040 00000000`: a cnt=3 INC run at method 0x1160
+ * whose THIRD data word is exactly zero and is immediately followed by a
+ * 52-word zero region - the read caught the client's push buffer after
+ * part of it had been reused/cleared. The same client writes valid A(2)
+ * values in the other windows of the same push (0x38200040/0x38200600/
+ * 0x38400600), so the zero is a torn read, not client content; and
+ * NUMERICAL_TYPE=0 is never a legitimate client write. Guard: for INC
+ * runs in the SET_VERTEX_ATTRIBUTE_A/B families (0x1160..0x11dc) drop a
+ * data word that is exactly zero, splitting the run so the remaining
+ * words keep their methods (the attribute then keeps the value the
+ * ATTR-PRELUDE or the previous frame wrote). Default 1; live-tunable.
+ */
+static u32 gsp_phys_rmcall_gr_attr_zero_fix = 1;
+module_param_named(sema_gl_attr_zero_fix, gsp_phys_rmcall_gr_attr_zero_fix, uint, 0644);
+MODULE_PARM_DESC(sema_gl_attr_zero_fix,
+ "Drop torn-read zero data words in the SET_VERTEX_ATTRIBUTE_A/B runs (0x1160..0x11dc) of 3D replays, splitting the run (default 1)");
+
/* (SESSION 153-CONTINUED-53 MME prelude knob is declared before
* gsp_phys_rmcall_build_gr_launch, its reader.) */
@@ -20220,6 +20244,56 @@ static u32 gsp_phys_rmcall_gr_3d_patch_window(const u32 *in, u32 n, u32 *out,
continue;
}
memcpy(&out[wout], &in[off], (size_t)span * 4);
+ /*
+ * SESSION 153-CONTINUED-58: torn-read zero guard - see the
+ * sema_gl_attr_zero_fix comment. Only INC runs (op 1) whose
+ * data words advance one method each; the attribute runs are
+ * exactly this shape. Rebuild the run in place, skipping
+ * exactly-zero words and re-targeting the surviving words'
+ * methods (a zero word's method is simply never written, so
+ * the attribute keeps its prelude/previous-frame value).
+ */
+ if (READ_ONCE(gsp_phys_rmcall_gr_attr_zero_fix) &&
+ op == 1u && cnt && addr >= 0x1160u && addr <= 0x11dcu) {
+ u32 k, k0 = 0, L = 0, wr = wout;
+ u32 subch = (hdr >> 13) & 0x7u;
+
+ for (k = 0; k <= cnt; k++) {
+ bool bad = (k < cnt) &&
+ (out[wout + 1u + k] == 0u);
+
+ if (!bad && k < cnt) {
+ if (!L)
+ k0 = k;
+ out[wr + 1u] = out[wout + 1u + k];
+ wr++;
+ L++;
+ continue;
+ }
+ if (L) {
+ u32 naddr = addr + 4u * k0;
+ u32 nhdr = (1u << 29) |
+ (L << 16) |
+ ((naddr >> 2) & 0x1fffu) |
+ (subch << 13);
+
+ out[wr - L] = nhdr;
+ L = 0;
+ }
+ if (bad) {
+ static u32 az_log;
+
+ if (az_log < 64) {
+ az_log++;
+ pr_info("vgsp-gr: ATTR-ZERO addr=0x%x word=%u/%u off=%u dropped (torn-read zero; attribute keeps its prelude value)\n",
+ addr + 4u * k, k,
+ cnt, off);
+ }
+ }
+ }
+ /* +1: the rebuilt run still needs its (new) header word */
+ span = (wr - wout) + 1u;
+ }
{
/*
* SESSION 153-CONTINUED-14: live data patch (BEGIN
@@ -20728,8 +20802,8 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
u32 qmd_rel_off = 0, ch_rel_off = 0;
u32 poll = 0, w0 = 0, w1 = 0, grpoll_n = 0;
bool sem_gated = false;
- static u32 sked_prev[24];
- static u32 sked_sample[24];
+ static u32 sked_prev[28];
+ static u32 sked_sample[28];
static u32 sked_tick;
static bool sked_first;
/*
@@ -22581,6 +22655,21 @@ gr_page_unmapped:
sked_sample[21] = ioread32(bar0 + 0x00400708u);
sked_sample[22] = ioread32(bar0 + 0x0040070cu);
sked_sample[23] = ioread32(bar0 + 0x00400710u);
+ /*
+ * SESSION 153-CONTINUED-58: the front-end DECODE
+ * STATE EX registers (NV_PGRAPH_PRI_FE_DECODE_STATE_EX
+ * 0x40a630..0x40a63c, 4 slots): MME_PC 11:0,
+ * MME_MACRO_ADDR 21:12, MME_GENERATED bit 31 - the
+ * front end's own record of the last MME-generated
+ * method write, which names the macro (address) and
+ * its pc for the class error even when the trapped
+ * registers are already back to the 0xbadf priv
+ * poison. Sampled per tick like the trap set.
+ */
+ sked_sample[24] = ioread32(bar0 + 0x0040a630u);
+ sked_sample[25] = ioread32(bar0 + 0x0040a634u);
+ sked_sample[26] = ioread32(bar0 + 0x0040a638u);
+ sked_sample[27] = ioread32(bar0 + 0x0040a63cu);
if (sked_first ||
memcmp(sked_sample, sked_prev,
sizeof(sked_sample))) {
@@ -22609,6 +22698,16 @@ gr_page_unmapped:
(sked_sample[20] >> 24) & 1u,
sked_sample[23] & 0xfffu,
(sked_sample[23] >> 12) & 0xffu);
+ if (sked_sample[24] || sked_sample[25] ||
+ sked_sample[26] || sked_sample[27])
+ pr_info("vgsp-gr: sked fed0=%08x fed1=%08x fed2=%08x fed3=%08x (pc0=%u mac0=0x%x gen0=%u)\n",
+ sked_sample[24],
+ sked_sample[25],
+ sked_sample[26],
+ sked_sample[27],
+ sked_sample[24] & 0xfffu,
+ (sked_sample[24] >> 12) & 0x3ffu,
+ (sked_sample[24] >> 31) & 1u);
memcpy(sked_prev, sked_sample,
sizeof(sked_sample));
sked_first = false;