summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 3a24967..fe1f7b0 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -17906,6 +17906,30 @@ MODULE_PARM_DESC(sema_gl_sph_version,
"Emit the Turing channel-init SET_SPH_VERSION/CHECK_SPH_VERSION pair (0x16a4/0x16a8 <- 0x00040004) ahead of each replayed 3D window (default 1; A/B with 0 reproduces the Shader Program Header 9/11/18 fault)");
/*
+ * SESSION 153-CONTINUED-90: SET_SHADER_EXCEPTIONS (0x1528 <- 0).
+ *
+ * NVIDIA's own Turing 3D channel init (_nv3dInitChannelTuring) pushes this
+ * FIRST, with the comment "Disable shader exceptions. This matches OpenGL
+ * driver behavior." The client's captured init stream carries the write too
+ * (sema-pushraw `off=0x5a4 op=4 addr=0x1528 v0=0`). The replayed context
+ * never receives it: the emitted push (PB-FAULT-DUMP) goes SET_OBJECT ->
+ * SPH version pair -> MME version with no 0x1528 run, so the DS keeps
+ * raising "Graphics Exception: Shader Program Header 5/9/10/11 Error" on
+ * every draw whose fetched SPH it would tolerate with exceptions disabled -
+ * and the exception poisons the channel before any store retires. An
+ * executing r1294 launch names the consequence: the first post-exception
+ * method write reports `ChID 0001, Class 0000c597, Offset 0000022c, Data
+ * 00000800` (SET_GO_IDLE_TIMEOUT poisoned by the exception state).
+ * Emitted right after SET_OBJECT, exactly like the reference init order.
+ * Default 1; A/B with 0 restores the old behavior.
+ */
+static bool gsp_phys_rmcall_gr_shader_exc = true;
+module_param_named(sema_gl_shader_exc, gsp_phys_rmcall_gr_shader_exc,
+ bool, 0644);
+MODULE_PARM_DESC(sema_gl_shader_exc,
+ "Emit SET_SHADER_EXCEPTIONS (0x1528) <- 0 after SET_OBJECT like _nv3dInitChannelTuring (default 1)");
+
+/*
* SESSION 153-CONTINUED-87: the missing TESS_CONTROL/PIXEL program binds.
* The client's real channel state binds every pipeline stage once per
* context; the captured init-push image (guest RAM scrape) carries
@@ -18570,6 +18594,28 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
(GSP_PHYS_RMCALL_GR_SET_OBJECT >> 2);
*p++ = GSP_PHYS_RMCALL_CLASS_GR_3D;
/*
+ * SESSION 153-CONTINUED-90: SET_SHADER_EXCEPTIONS (0x1528)
+ * <- 0, the first write of NVIDIA's own Turing 3D channel
+ * init (see the sema_gl_shader_exc knob): with shader
+ * exceptions enabled the DS raises "Shader Program Header
+ * 5/9/10/11" on the draws whose SPHs it would otherwise
+ * tolerate, and the raised exception poisons the channel
+ * before any store retires.
+ */
+ if (READ_ONCE(gsp_phys_rmcall_gr_shader_exc)) {
+ static u32 shader_exc_log;
+
+ *p++ = ((u32)GSP_PHYS_RMCALL_METHOD_IMM << 29) |
+ (1u << 16) | (0x1528u >> 2);
+ *p++ = 0u;
+ if (shader_exc_log < 8u) {
+ shader_exc_log++;
+ pr_info("vgsp-gr: SHADER-EXC emitted 0x1528 <- 0 (2 words; pos=%u h=0x%x push=0x%llx)\n",
+ (u32)(p - pb), req->h_object,
+ req->push_va);
+ }
+ }
+ /*
* SESSION 153-CONTINUED-86: the Turing channel-init SPH version
* pair (see the sema_gl_sph_version knob). Emitted on EVERY
* replayed 3D window (3 words, idempotent): the DS validates
@@ -21754,6 +21800,75 @@ static u32 gsp_phys_gr_wit_report(const char *where)
return changed;
}
+/*
+ * SESSION 153-CONTINUED-90: SPH-alias receipt. The DS I-fetch of a bound
+ * stage reaches the program-family VA through the shadow VA the relocation
+ * picked, and the PTE of that shadow VA names the physical page the engine
+ * reads. Log the mapping choice (launch page set vs trusted resolver), the
+ * shadow VA and the mapped HPA, then read the fetch words back through the
+ * host direct map of that very page (for a RAM-backed HPA the direct map is
+ * content-identical to the engine's PTE-based read), so "which physical page
+ * does the DS I-fetch actually read" is provable from the log alone. Bounded
+ * per boot; foreign (non-RAM) HPAs are named but not dereferenced.
+ */
+static void gsp_phys_gr_sph_alias_receipt(u64 page, u64 va, u64 sh, u64 hpa,
+ const char *via)
+{
+ static u32 sph_alias_n;
+ u32 w[8] = { 0 };
+ u32 off = (u32)(va & (GSP_PHYS_PAGE_SIZE - 1u));
+ bool rd = false;
+
+ if (sph_alias_n >= 48u)
+ return;
+ sph_alias_n++;
+ if (pfn_valid((unsigned long)(hpa >> PAGE_SHIFT))) {
+ const u8 *p = (const u8 *)__va(hpa + off);
+ u32 i;
+
+ for (i = 0; i < 8u; i++)
+ w[i] = get_unaligned_le32(p + (size_t)i * 4u);
+ rd = true;
+ }
+ pr_info("vgsp-gr: SPH-ALIAS-%s page=0x%llx va=0x%llx off=0x%x shadow=0x%llx hpa=0x%llx rd=%u w8=%08x %08x %08x %08x %08x %08x %08x %08x\n",
+ via, page, va, off, sh, hpa, rd ? 1u : 0u,
+ w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7]);
+}
+
+/*
+ * SESSION 153-CONTINUED-90: A/B canary for the DS fetch path. When set,
+ * every program-family operand the window relocates maps a dedicated canary
+ * page (a deterministic 0xcc00cc00|idx pattern) instead of the resolved
+ * guest page. The DS error set either changes (the DS does fetch through
+ * this shadow VA) or stays byte-identical (something else supplies the
+ * stage start, e.g. the QMD program pointer path). Live-flippable.
+ */
+static bool gsp_phys_gr_sph_canary;
+module_param_named(sema_gl_sph_canary, gsp_phys_gr_sph_canary, bool, 0644);
+MODULE_PARM_DESC(sema_gl_sph_canary,
+ "Map program-family shadow VAs to a canary page (SPH fetch-path A/B)");
+static struct gsp_phys_boot_chunk sph_canary_chunk;
+static bool sph_canary_ready;
+
+static u64 gsp_phys_gr_sph_canary_hpa(void)
+{
+ if (!sph_canary_ready) {
+ u8 *p;
+ u32 i;
+
+ if (!boot_stage.pdev ||
+ gsp_phys_chunk_alloc(boot_stage.pdev, &sph_canary_chunk, 1))
+ return 0;
+ p = gsp_phys_chunk_page_va(&sph_canary_chunk, 0);
+ if (!p)
+ return 0;
+ for (i = 0; i < GSP_PHYS_PAGE_SIZE / 4u; i++)
+ ((u32 *)p)[i] = 0xcc00cc00u | (i & 0xffu);
+ sph_canary_ready = true;
+ }
+ return (u64)gsp_phys_chunk_page_dma(&sph_canary_chunk, 0);
+}
+
static bool gsp_phys_rmcall_gr_3d_reloc(u32 *up_w, u32 *lo_w,
const struct gsp_phys_gr_submit *req,
u32 *n_shadow)
@@ -21766,6 +21881,30 @@ static bool gsp_phys_rmcall_gr_3d_reloc(u32 *up_w, u32 *lo_w,
if (!va || !page)
return false;
/*
+ * SESSION 153-CONTINUED-90: must run before every resolution stage so
+ * the canary cannot be shadowed by an earlier (surd) alias hit.
+ */
+ if (READ_ONCE(gsp_phys_gr_sph_canary) && req->prog_va &&
+ page == (req->prog_va & ~(u64)(GSP_PHYS_PAGE_SIZE - 1))) {
+ u64 chpa = gsp_phys_gr_sph_canary_hpa();
+ u32 line3 = 0;
+
+ if (chpa &&
+ *n_shadow < GSP_PHYS_RMCALL_GR_SHADOW_PAGES &&
+ !gsp_phys_rmcall_gr_map_shadow_locked(*n_shadow, chpa,
+ &sh, &line3)) {
+ if (line3 != 0xffffffffu)
+ (*n_shadow)++;
+ sh |= va & (GSP_PHYS_PAGE_SIZE - 1);
+ gsp_phys_gr_sph_alias_receipt(page, va, sh, chpa,
+ "canary");
+ *lo_w = (*lo_w & 0x3u) | ((u32)sh & 0xfffffffcu);
+ *up_w = (*up_w & ~0xffu) |
+ ((u32)(sh >> 32) & 0xffu);
+ return true;
+ }
+ }
+ /*
* SESSION 153-CONTINUED-63: rec-over-alias preference. When the fill
* tracked the render target through the bounce lane (every page
* resolved into contiguous data recs), rewrite the operand to the
@@ -21861,6 +22000,11 @@ static bool gsp_phys_rmcall_gr_3d_reloc(u32 *up_w, u32 *lo_w,
/* CONT-73: shadow VA maps this guest HPA 1:1. */
gsp_phys_gr_wit_note(page, req->pages[i].hpa);
sh |= va & (GSP_PHYS_PAGE_SIZE - 1);
+ if (req->prog_va &&
+ page == (req->prog_va & ~(u64)(GSP_PHYS_PAGE_SIZE - 1)))
+ gsp_phys_gr_sph_alias_receipt(page, va, sh,
+ req->pages[i].hpa,
+ "pages");
*lo_w = (*lo_w & 0x3u) | ((u32)sh & 0xfffffffcu);
*up_w = (*up_w & ~0xffu) | ((u32)(sh >> 32) & 0xffu);
return true;
@@ -21890,6 +22034,13 @@ static bool gsp_phys_rmcall_gr_3d_reloc(u32 *up_w, u32 *lo_w,
/* CONT-73: shadow VA maps this guest HPA 1:1. */
gsp_phys_gr_wit_note(page, r.hpa);
sh |= va & (GSP_PHYS_PAGE_SIZE - 1);
+ if (req->prog_va &&
+ page ==
+ (req->prog_va &
+ ~(u64)(GSP_PHYS_PAGE_SIZE - 1)))
+ gsp_phys_gr_sph_alias_receipt(page, va, sh,
+ r.hpa,
+ "resolve");
*lo_w = (*lo_w & 0x3u) | ((u32)sh & 0xfffffffcu);
*up_w = (*up_w & ~0xffu) | ((u32)(sh >> 32) & 0xffu);
return true;