summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-01 21:42:00 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-01 21:42:00 -0500
commitd61bf4e99e5119f7a6b8ee43e745fbbf4fd5c4ef (patch)
treedec545929515d600b7a9e2b8fc43d29233dd4047
parentf7bc705a8a61e6ad11cd23b5fabd5a86e62ae34c (diff)
downloadopen-iov-d61bf4e99e5119f7a6b8ee43e745fbbf4fd5c4ef.tar.gz
open-iov-d61bf4e99e5119f7a6b8ee43e745fbbf4fd5c4ef.zip
vgsp: CONT-101 - sema-scratch18 watch (scan every decoded push on every channel for 0x3460 SET_MME_SHADOW_SCRATCH(0x18), log up to 24 hits, publish first value via gsp_sema_mme_scratch18_get) + sema_gl_mme_seed/seed_val/seed_xlat (emit [op1 cnt1 m=0x3460][value] ahead of every replayed 3D window; xlat translates value page through launch shadow mapper before >>8) - DECISIVE: client NEVER writes 0x3460 (0 hits across r1348-52 all channels); seed works end-to-end (MME-SEED scratch 0x18 <- 0x000a0000 va=0xa000000 xlat=1) but wall not cleared: MME-FAST trap=80002058 data=019b0900 grfifo 04041602->00000001 park events=2 - trap is window's own relocated program pair (pair addr=0x2054 va=0x4350900 -> 0x19b0900) and fires BEFORE MME consumes seed; DESIGNED FIX WORKS LIVE: sema_gl_prog_guest_va=Y -> PROG-GUEST-VA keep addr=0x2054 va=0x4400900 (Tier-1 identity; operand verbatim) -> ZERO trap=80002058 thereafter; r1352 (keep from boot) got session's FIRST MME-generated evidence (gen0=1) then lottery outcome events=4 (poison) esr->0xbadf1201 WEDGE-REARM engine still wedged; GATE1 black 0/900 pages NO-STORES - next: boot r1347 richest config (nop_drop=1<<0 slot 0 dropped) PLUS sema_gl_prog_guest_va=1 from insmod (removes 0x2058 trap class the seed cannot touch); check stores before re-arming slot 0 with seed; 0xd18 golden value open but subordinate (vGPU client never emits it) - SESSION 153 r1348-r1352
-rw-r--r--kernel/gsp_phys_booter.c100
-rw-r--r--kernel/gsp_sema_service.c86
-rw-r--r--kernel/gsp_sema_service.h10
3 files changed, 194 insertions, 2 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 42fb8f2..663f276 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -18228,6 +18228,41 @@ MODULE_PARM_DESC(sema_sph_region_base,
"Program-region base override (0 = launch program family page; nonzero = explicit engine-side base)");
/*
+ * SESSION 153-CONTINUED-101: MME fixed-constant-buffer scratch seed
+ * (SET_MME_SHADOW_SCRATCH(0x18), method 0x3460).
+ *
+ * mmeCodeOGL_C597_SETUP_FIXED_CONST (macro slot 0) reads shadow scratch
+ * 0x18/0xd18 via STATE and unconditionally emits its high/low halves as
+ * SET_CONSTANT_BUFFER_SELECTOR_B/C (the compiled C597 form carries NO
+ * bug2548370 branch: the config table says no972630). With the replay
+ * context's scratch at 0 the macro emits selector B/C = 0 and the draw's
+ * constant fetch has no address. The client's own write (gf100Init-
+ * ConstantBuffers: (u32)(fixed CB VA >> 8)) is a once-per-channel event
+ * the ladder never receives, so the builder seeds it ahead of the
+ * window. Value source: sema_gl_mme_seed_val when nonzero, else the
+ * client's own captured write (gsp_sema_mme_scratch18_get). With
+ * sema_gl_mme_seed_xlat (default 1) the page is translated through the
+ * launch's own page set / shadow mapping first (the same relocator the
+ * window operand pairs use) so the emitted selector resolves in the
+ * engine's address space; on MISS the raw value is emitted (the A/B
+ * control). Default off; live-tunable.
+ */
+static bool gsp_phys_rmcall_gr_mme_seed;
+module_param_named(sema_gl_mme_seed, gsp_phys_rmcall_gr_mme_seed, bool, 0644);
+MODULE_PARM_DESC(sema_gl_mme_seed,
+ "Seed MME shadow scratch 0x18 (method 0x3460) with the fixed-CB base>>8 ahead of replayed 3D windows (default 0)");
+static u32 gsp_phys_rmcall_gr_mme_seed_val;
+module_param_named(sema_gl_mme_seed_val, gsp_phys_rmcall_gr_mme_seed_val,
+ uint, 0644);
+MODULE_PARM_DESC(sema_gl_mme_seed_val,
+ "Explicit scratch 0x18 value (fixed CB VA>>8); 0 = use the client's captured 0x3460 write");
+static bool gsp_phys_rmcall_gr_mme_seed_xlat = true;
+module_param_named(sema_gl_mme_seed_xlat, gsp_phys_rmcall_gr_mme_seed_xlat,
+ bool, 0644);
+MODULE_PARM_DESC(sema_gl_mme_seed_xlat,
+ "Translate the seed value's page to the engine-side shadow/identity VA before emitting (default 1; 0 = raw)");
+
+/*
* SESSION 153-CONTINUED-93: additionally emit the legacy program-region
* pair (0x1608/0x160c) beside the MME shadow pair (see the emission site).
* Default 0 (A/B; the DS snapshot registers share the legacy pair's names).
@@ -18558,8 +18593,7 @@ MODULE_PARM_DESC(sema_gl_surf_prelude,
* seen on the client's 0x402094c push) does not count - the surface
* prelude is injected for it too.
*/
-static bool gsp_phys_gr_window_has_surface(const u32 *win, u32 n)
-{
+static bool gsp_phys_gr_window_has_surface(const u32 *win, u32 n){
u32 off = 0;
while (off < n) {
@@ -18597,6 +18631,13 @@ static bool gsp_phys_gr_window_has_surface(const u32 *win, u32 n)
* channel long before the launch), so the replay must not either.
* Returns the block size in dwords.
*/
+/* SESSION 153-CONTINUED-101: forward declaration - the seed emission in
+ * gsp_phys_rmcall_build_gr_launch (below) translates the seed page through
+ * the same relocator the window operand pairs use (defined further down). */
+static bool gsp_phys_rmcall_gr_3d_reloc(u32 *up_w, u32 *lo_w,
+ const struct gsp_phys_gr_submit *req,
+ u32 *n_shadow);
+
static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
const struct gsp_phys_gr_submit *req,
const u32 *qmd, u64 qmd_va,
@@ -19112,6 +19153,61 @@ static u32 gsp_phys_rmcall_build_gr_launch(u32 *pb,
}
}
/*
+ * SESSION 153-CONTINUED-101: MME fixed-constant-buffer scratch
+ * seed (see the sema_gl_mme_seed* knobs). mmeCodeOGL_C597_
+ * SETUP_FIXED_CONST (slot 0) emits SET_CONSTANT_BUFFER_
+ * SELECTOR_B/C from shadow scratch 0x18/0xd18; the replay
+ * context never received the client's once-per-channel write
+ * (gf100InitConstantBuffers pushes method 0x3460), so the
+ * macro read 0 and the selector went empty. Emit the seed
+ * ahead of the window; the value is the fixed CB address>>8,
+ * page-translated to the launch's shadow/identity mapping when
+ * sema_gl_mme_seed_xlat is set (see gsp_phys_rmcall_gr_3d_
+ * reloc - same machinery as the operand pairs).
+ */
+ if (READ_ONCE(gsp_phys_rmcall_gr_mme_seed)) {
+ static u32 mme_seed_log;
+ u32 sv = READ_ONCE(gsp_phys_rmcall_gr_mme_seed_val);
+ bool have = sv != 0u;
+
+ if (!have)
+ have = gsp_sema_mme_scratch18_get(&sv);
+ if (have && sv &&
+ (u32)(p - pb) + 8u < GSP_PHYS_RMCALL_GR_METHOD_WORDS) {
+ u64 va = (u64)sv << 8;
+ bool xl = false;
+
+ if (READ_ONCE(gsp_phys_rmcall_gr_mme_seed_xlat)
+ && va) {
+ u32 up_w = (u32)((va >> 32) & 0xffu);
+ u32 lo_w = (u32)va & 0xfffffffcu;
+ u32 n_sh = 0;
+
+ if (gsp_phys_rmcall_gr_3d_reloc(
+ &up_w, &lo_w, req, &n_sh)) {
+ va = ((u64)(up_w & 0xffu)
+ << 32) |
+ (u64)(lo_w & 0xfffffffcu);
+ sv = (u32)(va >> 8);
+ xl = true;
+ }
+ }
+ *p++ = ((u32)GSP_PHYS_RMCALL_METHOD_IMM << 29) |
+ (1u << 16) | (0x3460u >> 2);
+ *p++ = sv;
+ if (mme_seed_log < 16u) {
+ mme_seed_log++;
+ pr_info("vgsp-gr: MME-SEED scratch 0x18 <- 0x%08x (va=0x%llx xlat=%u) h=0x%x push=0x%llx\n",
+ sv, va, xl, req->h_object,
+ req->push_va);
+ }
+ } else if (mme_seed_log < 16u) {
+ mme_seed_log++;
+ pr_info("vgsp-gr: MME-SEED no value (client 0x3460 not seen yet; set sema_gl_mme_seed_val) h=0x%x\n",
+ req->h_object);
+ }
+ }
+ /*
* SESSION 153-CONTINUED-93: the LEGACY program-region pair
* (0x1608/0x160c = the pre-Volta SET_PROGRAM_REGION_A/B whose
* names the DS's own snapshot registers
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 234932c..a3ee6f3 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -14738,6 +14738,88 @@ static void svc_mme_census(const u8 *buf, u32 len, u64 push_va, u32 h_object)
}
/*
+ * SESSION 153-CONTINUED-101: MME fixed-constant-buffer scratch watch.
+ *
+ * mmeCodeOGL_C597_SETUP_FIXED_CONST (macro slot 0) is the only reader of
+ * MME shadow scratch 0x18/0xd18 (MME_SCRATCH_FIXED_CONSTANT_BUFFER =
+ * 0x10 + RM_MME_FIRST_USABLE_SHADOW_SCRATCH); its compiled C597 form DOES
+ * NOT include the bug2548370 branch, so it unconditionally emits
+ * SET_CONSTANT_BUFFER_SELECTOR_B/C = cbAddr[31:24]/[23:0]<<8 from that
+ * scratch. The value is written once per channel/context by the client's
+ * own gf100InitConstantBuffers: method 0x3460 (SET_MME_SHADOW_SCRATCH
+ * (0x18)) <- (u32)(fixed constant buffer VA >> 8). The replayed ladder
+ * context never receives that once-per-channel write, so the macro reads
+ * 0 and emits an empty CB selector; the draw then fetches constants from
+ * address 0. This watch records the client's own write (any channel, any
+ * push that decodes) and publishes the first value so the GR launch
+ * builder can seed scratch 0x18 ahead of the window (sema_gl_mme_seed).
+ * Value is stored exactly as pushed (client VA >> 8). Read-only.
+ */
+static u32 svc_scratch18_val;
+static bool svc_scratch18_seen;
+static u32 svc_scratch18_log;
+
+bool gsp_sema_mme_scratch18_get(u32 *val)
+{
+ if (svc_scratch18_seen && val)
+ *val = READ_ONCE(svc_scratch18_val);
+ return svc_scratch18_seen;
+}
+
+static void svc_scratch18_watch(const u8 *buf, u32 len, u64 push_va,
+ u32 h_object)
+{
+ u32 off = 0;
+
+ if (svc_scratch18_seen && svc_scratch18_log >= 24u)
+ return;
+ while (off + 4u <= len) {
+ u32 hdr, op, cnt, addr;
+
+ memcpy(&hdr, buf + off, 4);
+ op = (hdr >> 29) & 7u;
+ cnt = (hdr >> 16) & 0xfffu;
+ addr = (hdr & 0xfffu) << 2;
+ if ((op == 1u || op == 3u || op == 5u) && cnt &&
+ off + 4u + cnt * 4u <= len) {
+ if (addr == 0x3460u) {
+ u32 val;
+
+ memcpy(&val, buf + off + 4, 4);
+ if (!svc_scratch18_seen) {
+ svc_scratch18_seen = true;
+ WRITE_ONCE(svc_scratch18_val, val);
+ }
+ if (svc_scratch18_log < 24u) {
+ svc_scratch18_log++;
+ pr_info("sema-scratch18: h=0x%x va=0x%llx off=0x%x op=%u cnt=%u val=0x%08x (SET_MME_SHADOW_SCRATCH(0x18); fixed-CB base>>8)\n",
+ h_object, push_va, off, op, cnt,
+ val);
+ }
+ off += 4u + cnt * 4u;
+ continue;
+ }
+ off += 4u + cnt * 4u;
+ continue;
+ }
+ if (op == 4u && addr == 0x3460u) {
+ u32 val = (hdr >> 16) & 0x1fffu;
+
+ if (!svc_scratch18_seen) {
+ svc_scratch18_seen = true;
+ WRITE_ONCE(svc_scratch18_val, val);
+ }
+ if (svc_scratch18_log < 24u) {
+ svc_scratch18_log++;
+ pr_info("sema-scratch18: h=0x%x va=0x%llx off=0x%x op=4 immd val=0x%08x (SET_MME_SHADOW_SCRATCH(0x18))\n",
+ h_object, push_va, off, val);
+ }
+ }
+ off += 4u;
+ }
+}
+
+/*
* SESSION 153-CONTINUED-94: client init-push capture + local-memory census.
*
* CONT-93's "single most concrete next fix" was that the GL driver's
@@ -16241,6 +16323,10 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
if (ch)
svc_mme_census(buf, len, push_va, ch->h_object);
+ /* SESSION 153-CONTINUED-101: fixed-CB scratch (0x3460) watch, any channel. */
+ if (ch)
+ svc_scratch18_watch(buf, len, push_va, ch->h_object);
+
/* SESSION 153-CONTINUED-94: init-push capture + local-memory census. */
if (ch)
svc_init_push_scan(buf, len, push_va, ch->h_object);
diff --git a/kernel/gsp_sema_service.h b/kernel/gsp_sema_service.h
index f2a40ee..7efc2f3 100644
--- a/kernel/gsp_sema_service.h
+++ b/kernel/gsp_sema_service.h
@@ -558,6 +558,16 @@ bool gsp_sema_gr_surf_recs(u64 *va, u32 *n);
u64 gsp_sema_mme_sa_get(u32 *entries, u32 n);
/*
+ * SESSION 153-CONTINUED-101: the client's own SET_MME_SHADOW_SCRATCH(0x18)
+ * write (method 0x3460) - mmeCodeOGL_C597_SETUP_FIXED_CONST (slot 0) reads
+ * shadow scratch 0x18/0xd18 via STATE and emits it as the fixed-function
+ * constant-buffer selector (SET_CONSTANT_BUFFER_SELECTOR_B/C). Returns
+ * true (and stores the value exactly as pushed: fixed-CB address >> 8)
+ * once any decoded client push carried the write. false until then.
+ */
+bool gsp_sema_mme_scratch18_get(u32 *val);
+
+/*
* SESSION 153-CONTINUED-87: the SPH VERSION of the live program images
* (sema_gl_vs/ps_hex blobs), so the GR launch builder emits a
* SET_SPH_VERSION window that MATCHES the images the engine will fetch