summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-15 11:17:06 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-15 11:17:06 -0500
commitb9e7e84249a28a5e296a0f97e00a3bdf2e5ce6df (patch)
tree6ddc4ee932ee6f505a744c94ff26ee23416c75e5
parent444ae2c1dfde6a66e414b7f2ff9c5813ec50942d (diff)
downloadopen-iov-b9e7e84249a28a5e296a0f97e00a3bdf2e5ce6df.tar.gz
open-iov-b9e7e84249a28a5e296a0f97e00a3bdf2e5ce6df.zip
vgsp: eng51 - emit the SPH-BIND stage block (budget fix), admit RT0-bearing draw-synth windows, preserve the last beef push, and default the DS stage-image A/B safe
- gsp_phys_booter.c: the synthesized SPH-BIND stage-block guard double-counted the already-emitted raster words (101 > 96), silently skipping j0/j2/j4/j5; pre=29 -> pre=84 and the DS stage VAs populate. Add the SPH-BIND-STAGE-SKIP receipt. - gsp_sema_service.c: sema_gl_win_rt0_admit (default 1) admits a beef draw-synth window whose FIRST colour-target write is a usable surface-class bind (RT0-FIRST-MISS witness); preserve the most recent beef push (>=256 B) for the gsp-phys-last-push debugfs dump; skip the non-RAM windows in the linear ring scan; fix the MME shadow-RAM index shift to (mthd >> 2) & 0xfff. - gsp_phys_booter.c: sema_gl_sph_vtg600 (default 0) and sema_gl_sph_vtg_j1 (default 0) are the stage-image A/B: binding family+0x600 poisons the DS (the engine-visible alias shadow there is the client's SASS upload), so keep the historical +0x900 zero page until a real VTG SPH is authored at an engine-visible VA. - tools/guest-diag/params-r1624.txt: enable sema_gl_win_rt0_admit. - wiki/Project-Status.md: 2026-11-15 status (MME chain completes and executes DRAW_IAB; DS stage image is the named gate).
-rw-r--r--kernel/gsp_phys_booter.c124
-rw-r--r--kernel/gsp_sema_service.c171
-rw-r--r--kernel/gsp_sema_service.h2
-rw-r--r--tools/guest-diag/params-r1624.txt1
-rw-r--r--wiki/Project-Status.md37
5 files changed, 317 insertions, 18 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index cf3107f..e43ba23 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -5280,7 +5280,7 @@ MODULE_PARM_DESC(sema_mme_post_ms,
*/
static u32 gsp_phys_mme_shadow_read(void __iomem *bar0, u32 nvclass, u32 mthd)
{
- iowrite32(nvclass | ((mthd & 0xfffu) << 16) | (1u << 30),
+ iowrite32(nvclass | (((mthd >> 2) & 0xfffu) << 16) | (1u << 30),
bar0 + 0x00404488u);
return ioread32(bar0 + 0x0040448cu);
}
@@ -19957,6 +19957,35 @@ module_param_named(sema_sph_bind_mask, gsp_phys_rmcall_gr_sph_bind_mask,
MODULE_PARM_DESC(sema_sph_bind_mask,
"Synth SPH-BIND slot mask (bit j = slot j; 0x20 = PS only, 0x01/0x10 = VSA/GS VTG image, 0x25 = VSA+PS) used when sema_gl_sph_bind=0");
+/*
+ * eng51 (CONT.512): the synthesized VSA/GS (j0/j4) bind the VTG SPH image.
+ * The historical address was family+0x900, but the live direct-GL family
+ * page reads zero there (c716: DS 0x86040624 with stage=01df0900,...).
+ * family+0x600 was tried as the VTG image (INLINE-WRITER: 0x020a0481), but
+ * the engine-visible alias shadow at +0x600 is the client's SASS upload
+ * (0x0b0b7208), so binding it poisons the DS (c718/c720: badf1201 with the
+ * j1 override off too). Default 0 = keep the historical +0x900 zero page
+ * until a real VTG SPH is authored at an engine-visible VA; A/B with 1.
+ */
+static bool gsp_phys_rmcall_gr_sph_vtg600;
+module_param_named(sema_gl_sph_vtg600, gsp_phys_rmcall_gr_sph_vtg600,
+ bool, 0644);
+MODULE_PARM_DESC(sema_gl_sph_vtg600,
+ "Bind the synthesized VSA/GS (j0/j4) stages to family+0x600 instead of the historical family+0x900 page (default 0: the live +0x600 alias shadow is SASS and poisons the DS)");
+
+/*
+ * eng51 A/B (c718): overriding the window's own slot-1 bind (j1) with the
+ * family+0x600 image is a separate question. c718 (override on) poisoned the
+ * DS (badf1201) while c716 (j0/j4 at 0x900, j1 at the client's 0x300 SASS
+ * pointer) reached 0x86040624, so the j1 override is default OFF until a
+ * same-boot A/B says otherwise.
+ */
+static bool gsp_phys_rmcall_gr_sph_vtg_j1;
+module_param_named(sema_gl_sph_vtg_j1, gsp_phys_rmcall_gr_sph_vtg_j1,
+ bool, 0644);
+MODULE_PARM_DESC(sema_gl_sph_vtg_j1,
+ "Also point the window's own slot-1 (VTG) bind at family+0x600 instead of the client's captured bind (default 0; c718 poison A/B)");
+
bool gsp_phys_rmcall_gr_sph_bind_value(void)
{
return READ_ONCE(gsp_phys_rmcall_gr_sph_bind);
@@ -30660,6 +30689,8 @@ gr_page_unmapped:
static u32 sph_bind_log;
u64 fam = req->prog_va &
~(u64)(GSP_PHYS_PAGE_SIZE - 1);
+ u64 vtg_va = READ_ONCE(gsp_phys_rmcall_gr_sph_vtg600) ?
+ (fam + 0x600u) : (fam + 0x900u);
u32 in[96], out[96];
u32 nfin = 0, nrun = 0, on = 0, odrop = 0, orel;
u32 bi;
@@ -30960,6 +30991,16 @@ gr_page_unmapped:
if (!va || nfin + 3u > 96u)
continue;
+ /*
+ * eng51: the window's own slot-1 bind can be
+ * a SASS pointer (c716: family+0x300 starts
+ * 0x0d0d7623); the VTG SPH image is at
+ * family+0x600. Point the VTG slot at the
+ * real image when the knob is on.
+ */
+ if (sl == 1u &&
+ READ_ONCE(gsp_phys_rmcall_gr_sph_vtg_j1))
+ va = vtg_va;
in[nfin++] = 0x20000000u | (2u << 16) |
((0x2014u + sl * 0x40u) >> 2);
in[nfin++] = (u32)(va >> 32) & 0xffu;
@@ -30981,9 +31022,7 @@ gr_page_unmapped:
(emit_j5 ? (bind_binding ? 8u : 7u) : 0u) +
(emit_gsimg ? (9u + ((gs_mode & 1u) ? 11u : 0u) +
((gs_ctx & 1u) ? 2u : 0u) +
- ((gs_ctx & 2u) ? 2u : 0u)) : 0u) +
- (emit_raster ? 17u : 0u) +
- (emit_raster_extra ? 16u : 0u)
+ ((gs_ctx & 2u) ? 2u : 0u)) : 0u)
<= 96u) {
/*
* SESSION 155 CONT 9: pair_safe emits each
@@ -31043,14 +31082,14 @@ gr_page_unmapped:
if (emit_j0) {
in[nfin++] = 0x20000000u | (2u << 16) |
(0x2014u >> 2);
- in[nfin++] = (u32)((fam + 0x900u) >> 32) & 0xffu;
- in[nfin++] = (u32)(fam + 0x900u) & 0xfffffffcu;
+ in[nfin++] = (u32)(vtg_va >> 32) & 0xffu;
+ in[nfin++] = (u32)vtg_va & 0xfffffffcu;
}
if (emit_j4) {
in[nfin++] = 0x20000000u | (2u << 16) |
(0x2114u >> 2);
- in[nfin++] = (u32)((fam + 0x900u) >> 32) & 0xffu;
- in[nfin++] = (u32)(fam + 0x900u) & 0xfffffffcu;
+ in[nfin++] = (u32)(vtg_va >> 32) & 0xffu;
+ in[nfin++] = (u32)vtg_va & 0xfffffffcu;
}
if (emit_j2) {
in[nfin++] = 0x20000000u | (2u << 16) |
@@ -31259,6 +31298,19 @@ gr_page_unmapped:
nrun++;
if (emit_gsimg)
nrun++;
+ } else if (sph_bind_log < 64u) {
+ /*
+ * eng51 (CONT.512): name the silent budget
+ * skip. Before this receipt the stage block
+ * (j0/j2/j4/j5/gsimg) could vanish while the
+ * prelude still emitted with only the j1 bind,
+ * leaving VSA/TCS/GS unbound and the DS latch
+ * at the a2040a04 class.
+ */
+ sph_bind_log++;
+ pr_info("vgsp-gr: SPH-BIND-STAGE-SKIP reason=budget nfin=%u mask=0x%x h=0x%x push=0x%llx\n",
+ nfin, sph_bind_mask, req->h_object,
+ req->push_va);
}
orel = gsp_phys_rmcall_gr_3d_patch_window(
in, nfin, out, &on, &odrop, req, &n_shadow,
@@ -31272,8 +31324,8 @@ gr_page_unmapped:
sph_bind_log++;
pr_info("vgsp-gr: SPH-BIND emitted fam=0x%llx win-binds=%u j0=0x%llx j2=0x%llx j4=0x%llx j5=0x%llx j1-type=0x11 rc=0x1a initblk=17 win=%u (pre=%u) h=0x%x push=0x%llx\n",
fam, req->n_prog_binds,
- fam + 0x900u, fam + 0x200u,
- fam + 0x900u, fam,
+ vtg_va, fam + 0x200u,
+ vtg_va, fam,
win3d_n, nfin,
req->h_object,
req->push_va);
@@ -37250,6 +37302,52 @@ static const struct file_operations gsp_phys_init_push_fops = {
};
/*
+ * eng51 (CONT.512): gsp-phys-last-push - the most recent >=4 KiB beef push
+ * (the direct-GL draw stream; c714: 0x4250110). Same text format as the
+ * init-push dump so the RT bind / draw methods can be decoded offline after
+ * the guest recycles its pushbuffer.
+ */
+static int gsp_phys_last_push_show(struct seq_file *m, void *unused)
+{
+ const u8 *buf;
+ u32 len, h, off;
+ u64 va;
+
+ buf = gsp_sema_last_cap_get(&len, &h, &va);
+ if (!len) {
+ seq_puts(m, "vgsp-last-push: empty (no later >=4 KiB beef push captured yet)\n");
+ return 0;
+ }
+ seq_printf(m, "vgsp-last-push: h=0x%x va=0x%llx len=%u\n", h, va, len);
+ for (off = 0; off + 4u <= len; off += 16u) {
+ u32 k, n = min_t(u32, 4u, (len - off) / 4u);
+
+ seq_printf(m, "%06x:", off);
+ for (k = 0; k < n; k++) {
+ u32 w;
+
+ memcpy(&w, buf + off + k * 4u, 4);
+ seq_printf(m, " %08x", w);
+ }
+ seq_putc(m, '\n');
+ }
+ return 0;
+}
+
+static int gsp_phys_last_push_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, gsp_phys_last_push_show, NULL);
+}
+
+static const struct file_operations gsp_phys_last_push_fops = {
+ .owner = THIS_MODULE,
+ .open = gsp_phys_last_push_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/*
* SESSION 153-CONTINUED-95: gsp-phys-ctx-dump - raw binary readback of the
* engine context buffer (see gsp_phys_ctx_readback_try). Empty until the
* first launch of the boot has run the CE readback.
@@ -37483,6 +37581,12 @@ int gsp_phys_boot_debugfs_init(void)
&gsp_phys_init_push_fops);
if (IS_ERR_OR_NULL(file))
pr_warn("vgsp-boot: debugfs file gsp-phys-init-push creation failed (init-push capture unavailable)\n");
+ /* eng51 (CONT.512): the most recent large beef push (direct-GL draw). */
+ file = debugfs_create_file("gsp-phys-last-push", 0444,
+ gsp_phys_debugfs_root, NULL,
+ &gsp_phys_last_push_fops);
+ if (IS_ERR_OR_NULL(file))
+ pr_warn("vgsp-boot: debugfs file gsp-phys-last-push creation failed (last-push capture unavailable)\n");
/*
* SESSION 153-CONTINUED-95: raw binary dump of the engine context
* buffer readback (64 KB from GSP_PHYS_RMCALL_VA_GR_CTX, taken once
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) {
diff --git a/kernel/gsp_sema_service.h b/kernel/gsp_sema_service.h
index b40dad2..f2a0777 100644
--- a/kernel/gsp_sema_service.h
+++ b/kernel/gsp_sema_service.h
@@ -305,6 +305,8 @@ void gsp_sema_service_fwd_gr_stats(u64 *req, u64 *ok, u64 *fallback,
* emitted the download-state local-memory block).
*/
const u8 *gsp_sema_init_cap_get(u32 *len, u32 *h, u64 *va, u32 *lmem_seen);
+/* eng51 (CONT.512): the most recent >=4 KiB beef push (direct-GL draw). */
+const u8 *gsp_sema_last_cap_get(u32 *len, u32 *h, u64 *va);
/*
* Discover and pin GR (compute) channel rings after the CE region of the
diff --git a/tools/guest-diag/params-r1624.txt b/tools/guest-diag/params-r1624.txt
index 4bf9afe..473a6f6 100644
--- a/tools/guest-diag/params-r1624.txt
+++ b/tools/guest-diag/params-r1624.txt
@@ -2,3 +2,4 @@ gsp_phys_gpu=1 gsp_phys_hazard_ack=1 gsp_phys_boot=1 gsp_phys_nocat=1 gsp_phys_f
sema_gr_grace_ms=500 sema_gl_mme_keep_done_across_recycle=1 sema_mme_prelude_cap_any=1
sema_gl_rt0_bind=1
sema_gl_mme_partial_keep_window=1 sema_gl_mme_pack_keep_gen=1 sema_gl_mme_cb_alias=1
+ sema_gl_win_rt0_admit=1
diff --git a/wiki/Project-Status.md b/wiki/Project-Status.md
index d556f4f..445b00d 100644
--- a/wiki/Project-Status.md
+++ b/wiki/Project-Status.md
@@ -10,7 +10,8 @@
> (the execution frontier). When this page and the docs disagree, the docs tree
> wins.
-Status: 2026-11-14, tree `master @ 339da842`. Tags: `[live]` proven with the
+Status: 2026-11-15, tree `master @ 444ae2c1` plus in-flight graphics changes in
+the working tree. Tags: `[live]` proven with the
stock guest driver; `[gated]` implemented, default-off or behind supervised
gates; `[wip]` partially implemented; `[wall]` current blocker; `[target]`
named success state; `[planned]` designed, not built.
@@ -28,7 +29,30 @@ named success state; `[planned]` designed, not built.
| Physical backend on real hardware (module-owned GPU running its real GSP-RM) | `[live]` boot, RPC session, object creation, copy-engine work and GR execution proven — the verified guest CUDA kernel clients execute through this backend, and graphics method streams execute on the engine ([`Graphics-Execution.md`](Graphics-Execution.md)) |
| Display and KMS on the emulated vGPU (nvidia-modeset/NvKms, `/dev/dri`, X) | `[live]` in the campaign configuration — the emulated display engine serves the guest's display push-buffer channels (notifier plus `UPDATE -> FINISHED`), nvidia-modeset/NvKms registers (`/dev/dri/card0`, `renderD128`, `fb0`), `nvidia-smi -L` enumerates and X settles. The X DDX idle-DMA/ScreenInit, USERD-latch lifetime, re-probe-thrash, Xorg kernel-mode-spin and flip-event walls were closed (X green for >10 minutes in a validated window); what remains is the per-boot **first-generation X start lottery**, which by 11-13/11-14 was the dominant throughput limiter for the graphics A/B runs (only an X started immediately after boot passes DDX DMA init; long stretches of dead starts, one green first-start boot). The display-capability seam is parameterised ([`Graphics-Execution.md`](Graphics-Execution.md)) |
| Multi-tenant isolation (mdev per VM, per-context page directories) | `[wip]` device-level coexistence works — multiple mediated devices with different emulated VRAM sizes and multiple guests coexist (two guests demonstrated); per-guest execution isolation for simultaneous CUDA guests is in progress |
-| OpenGL (3D graphics) | `[wip]` — the display/KMS stack registers, X and the stock NVIDIA GLX path are fully green (`glxinfo -B` returns 0 with OpenGL 4.6.0 and direct rendering; `glxgears` renders ~520 FPS with the emulated GPU's NVIDIA renderer), and the **first non-black GPU-rendered output** is proven: the pbuffer frame path produced 500/500 non-black 640x480 frames per run and captured videos (45.4 s on 2026-11-11; a 50 s 640x480 h264 capture on 2026-11-12). GZDoom reaches `V_Init: allocate screen` with its GL 4.6.0 context whenever the shared nvClip `modeNum` is even. **The direct-GL submission is now fully decoded:** no client push carries a method-grammar draw header — the channel's 9 NV906F entries tile one contiguous buffer and its per-frame work is carried as rewritten data-block blobs plus small state pushes (324/476/728 B) that invoke MME macros (the QMD-carrier hypothesis was tested and refuted). A content-gated FB-shadow rescue and a LOW-band rescue recover the recycled pushes: the client's draw-state push now opens a C597 section, is captured and marked for the verbatim 3D lane (the first direct-GL stream3d marks), and reaches the engine (`GR LAUNCH submitted`/`OK`, golden MME overlay accepted). **The current wall is MME macro completion:** the beef lane's 2799-word packed program cannot complete inside its <=2048-word block together with the 156-400-word draw window, so the load-only carrier gate drops each beef window and `live_gen` never promotes (a multi-part keep-window mechanism is committed default-off and enabled in the campaign params; A/B pending). RT routing was tested and refuted as the store cause (RT0 bind verified 16x but still `wrote=0`), and the earlier `CODESRC` fault-park class is prevented (zero `FAULT_PDE`/`WEDGE-REARM` on the validated boot). The window stays black (`px0=0`, `wrote=0`); the window/screen present path is unproven, and the X start lottery is the throughput limiter ([`OpenGL.md`](OpenGL.md)) |
+| OpenGL (3D graphics) | `[wip]` — the display/KMS stack registers, X and the stock NVIDIA GLX path are fully green (`glxinfo -B` returns 0 with OpenGL 4.6.0 and direct rendering; `glxgears` renders ~520 FPS with the emulated GPU's NVIDIA renderer), and the **first non-black GPU-rendered output** is proven: the pbuffer frame path produced 500/500 non-black 640x480 frames per run and captured videos (45.4 s on 2026-11-11; a 50 s 640x480 h264 capture on 2026-11-12). GZDoom reaches `V_Init: allocate screen` with its GL 4.6.0 context whenever the shared nvClip `modeNum` is even. **The direct-GL submission is now fully decoded:** no client push carries a method-grammar draw header — the channel's 9 NV906F entries tile one contiguous buffer and its per-frame work is carried as rewritten data-block blobs plus small state pushes (324/476/728 B) that invoke MME macros (the QMD-carrier hypothesis was tested and refuted). A content-gated FB-shadow rescue and a LOW-band rescue recover the recycled pushes: the client's draw-state push now opens a C597 section, is captured and marked for the verbatim 3D lane (the first direct-GL stream3d marks), and reaches the engine (`GR LAUNCH submitted`/`OK`, golden MME overlay accepted). **The MME chain now completes and executes the draw macro.** The multi-part
+keep-window mechanism won multi-frame windows; the part-launch poison was
+eliminated (the real fault was the client's own
+`SET_REPORT_SEMAPHORE`/`SET_NOTIFY` writes to client VAs that the host scratch
+page-table pool remaps — redirected to a mapped scratch slot; 49 cycles with
+zero poison and zero MMU faults); the 2799-word pack completes (2799/2799);
+engine-global completion plus keep-done-across-recycle produced the first
+`MME-PACK-REARM`; the fixed-CB region is aliased; and the released calls run
+macros through to **`DRAW_IAB` (`mac=0x22`)**. Two synthesized-prelude defects
+were then fixed: the SPH-BIND prelude self-destructed because an auto-dropped
+run broke its kept/final count (`444ae2c1`), and the stage block was silently
+skipped by a double-counted budget; with both fixed the prelude emits 84 words
+and the DS stage VAs populate (one validated boot carried the full post-REARM
+chain, `mac=0x22` and `DS 86040624`). The remaining gap is the **DS stage-0/1
+image**: the synthesized binds read `family+0x900` (zero in the live family
+page). Binding `family+0x600` was tried and poisons the DS (`badf1201`) because
+the engine-visible alias shadow there is the client's SASS upload, not an SPH
+header; the next step is authoring a VTG SPH at an engine-visible VA the
+client does not overwrite (`family+0x900`). Stores still miss (`wrote=0`,
+`px0=0`); the
+window/screen present path is unproven; and the per-boot binding lottery (the
+GL client usually rides the X channel in indirect mode, and X start keeps a
+first-generation lottery) is the throughput limiter
+([`OpenGL.md`](OpenGL.md)) |
| Vulkan (3D/compute) | `[wip]` — the guest Vulkan pipeline runs end to end on the emulated vGPU (device, allocation, pipeline, command buffer, fence, queue submit, readback) and the engine executes translated launches; frames are still black — program delivery and program-VA mapping are the frontier ([`Vulkan.md`](Vulkan.md)) |
| DirectX / Windows guests | `[planned]` (target) — no Windows guest booted yet; the architecture is the same emulation target ([`DirectX.md`](DirectX.md)) |
| Video (NVENC/NVDEC) | `[planned]` |
@@ -80,11 +104,10 @@ with direct rendering, `glxgears` renders ~520 FPS); the first non-black
GPU-rendered frames are proven off-screen (the pbuffer path produced a
500-frame 45.4 s video on 2026-11-11 and a 50 s capture on 2026-11-12), and
GZDoom reaches its screen-allocation stage with GL 4.6.0 on an even modeNum.
-The direct-GL submission is fully decoded (no classic draw header; the work is
-macro-driven and the client's state push now reaches the engine), but
-windowed/screen pixels remain the frontier (the MME multi-part program cannot
-yet complete, the store still misses, and X start keeps a first-generation
-lottery) — see [`OpenGL.md`](OpenGL.md). The
+The direct-GL submission is fully decoded, the MME multi-part program now
+completes and the draw macro executes, but windowed/screen pixels remain the
+frontier (the DS stage image is the last named gate before stores, and X start
+keeps a first-generation lottery) — see [`OpenGL.md`](OpenGL.md). The
risc-v-gsp-rm-debugger workbench
([`Riscv-GSP-RM-Debugger.md`](Riscv-GSP-RM-Debugger.md)) is the host-side
tooling used to study the firmware side of that frontier.