summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-05 13:22:14 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-05 13:22:14 -0500
commit22f77ffbf5ea2a3f6f678b825c7d296c16471175 (patch)
tree43905bb9014e1ee4aa3f86f9dabac6381d0ecc81 /kernel
parent17dcf049aca7b5a65d68389a110dc87d915a5393 (diff)
downloadopen-iov-22f77ffbf5ea2a3f6f678b825c7d296c16471175.tar.gz
open-iov-22f77ffbf5ea2a3f6f678b825c7d296c16471175.zip
vgsp-gr: read the fixed CB from the engine-visible page and never deliver a header-only VS image
The GL draw's VS was reading two wrong inputs. First, the fixed-CB copy resolved the client VA through a learned/FB layer first, so it read the emulated BAR1 vidmem shadow - a buffer the engine never writes - and delivered unrelated vidmem (r1490 first=09037223 00000004; r1482 oscillated between a float row, method words and zeros). Resolve the CB the way the engine does: channel VAS, every registered VAS page-table walk, then the GR relocation resolver; only a SYS answer is content-valid and an FB answer is flagged. The matrix gate now requires four normal-magnitude floats in c[0x0][0x80..0xbc] (r1492 accepted a method page as a matrix); a rejected read authors the identity MVP. Second, the captured 1536 B VTG upload is spliced at a page boundary: the delivered image was the SPH header plus ZERO SASS, so the VS executed no code. Reject captured program images whose SASS body [0x80,min(len,0x200)) is zero (the real-upload ring record, the 020a0481 cache and the window's own upload all pass the gate) and deliver the built-in known-good VTG image (the client's own SPH V4T1 020a0481 + SASS) at the bind VA instead; sema_gl_vs_img=0 restores the old behaviour. Diagnostics: cb-matrix/cb-const dumps of every VS-read constant block, SPH-ALIAS code4 words at the bind, and MME-VSTREAM post-relocation stream/limit/address payloads. r1491-r1493 (VP_MODE=6, RT0=1): the bind page now shows the real SASS (code4=ff047321 0000a0ff ...) and the CB/identity delivery is logged, but the draw still produces no fragments (retirement 0-3/900 = the forced MME seed pages only; xwd decoration rows only). Next wall: the vertex attribute/staging fetch (slot-57 0x39c8 data and the staging scratch 0x36/0x37), not the shader image or the fixed CB.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c32
-rw-r--r--kernel/gsp_sema_service.c439
2 files changed, 425 insertions, 46 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index d6ce2c2..494cb25 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -25510,7 +25510,9 @@ static void gsp_phys_gr_sph_alias_receipt(u64 page, u64 va, u64 sh, u64 hpa,
{
static u32 sph_alias_n;
u32 w[8] = { 0 };
+ u32 c[4] = { 0 };
u32 off = (u32)(va & (GSP_PHYS_PAGE_SIZE - 1u));
+ u32 coff = off + 0x80u; /* SPH code starts 0x80 B into the image */
bool rd = false;
if (sph_alias_n >= 48u)
@@ -25522,11 +25524,18 @@ static void gsp_phys_gr_sph_alias_receipt(u64 page, u64 va, u64 sh, u64 hpa,
for (i = 0; i < 8u; i++)
w[i] = get_unaligned_le32(p + (size_t)i * 4u);
+ if (coff + sizeof(c) <= GSP_PHYS_PAGE_SIZE) {
+ const u8 *cp = (const u8 *)__va(hpa + coff);
+
+ for (i = 0; i < 4u; i++)
+ c[i] = get_unaligned_le32(cp + (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",
+ 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 code4=%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]);
+ w[0], w[1], w[2], w[3], w[4], w[5], w[6], w[7],
+ c[0], c[1], c[2], c[3]);
}
/*
@@ -26877,6 +26886,25 @@ static u32 gsp_phys_rmcall_gr_3d_patch_window(const u32 *in, u32 n, u32 *out,
addr, wi, wv, lo);
}
}
+ /*
+ * r1491: the VERTEX_STREAM macro
+ * (CALL_MME_MACRO(2)=0x3810) carries
+ * [stream, limit_hi, limit_lo, addr_hi,
+ * addr_lo]; log the post-relocation words so
+ * the VTG stream base the engine will program
+ * is provable from the log. Bounded.
+ */
+ if (addr == 0x3810u && cnt >= 5u) {
+ static u32 vstream_log;
+
+ if (vstream_log < 8u) {
+ vstream_log++;
+ pr_info("vgsp-gr: MME-VSTREAM h=0x%x stream=%u limit=%08x:%08x addr=%08x:%08x (post-reloc)\n",
+ req ? req->h_object : 0u,
+ d[0], d[1], d[2],
+ d[3], d[4]);
+ }
+ }
}
wout += span;
off += 1u + cnt;
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 1a8efd6..5bc387e 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -8375,10 +8375,121 @@ static char *sema_gl_ps_hex;
module_param_named(sema_gl_ps_hex, sema_gl_ps_hex, charp, 0644);
MODULE_PARM_DESC(sema_gl_ps_hex,
"explicit PS program image (SPH+SASS hex, <=256 B) for pixel slots");
+/*
+ * r1492: deliver the known-good VTG image when the captured upload is
+ * header-only (page-splice corruption). Default 1; live A/B.
+ */
+static bool sema_gl_vs_img = true;
+module_param_named(sema_gl_vs_img, sema_gl_vs_img, bool, 0644);
+MODULE_PARM_DESC(sema_gl_vs_img,
+ "Deliver the built-in known-good VTG image (SPH+SASS) when the captured VS upload has no SASS body (default 1)");
static u8 svc_gl_prog[GSP_BRIDGE_INLINE_BYTES];
static u32 svc_gl_prog_len;
static u8 svc_gl_vs[GSP_BRIDGE_INLINE_BYTES];
/*
+ * r1492: known-good VTG program image (SPH V4T1 020a0481 + SASS), the
+ * client's own fixed-function vertex shader recovered from its init-push
+ * page. r1491 proved the runtime capture of this 1.4-1.5 KB upload can be
+ * spliced at a page boundary: the delivered bytes were the SPH header
+ * plus ZERO SASS, so the VS executed no code and the draw stored nothing.
+ * The captured image must pass svc_gl_img_code_ok(); when it does not,
+ * this image is delivered at the bind VA instead. A/B via
+ * sema_gl_vs_img=0 (captured image only) and overridden by sema_gl_vs_hex.
+ * The bytes are the client's compiled program (no private provenance).
+ */
+static const u8 svc_gl_vs_img[1408] = {
+
+ 0x81, 0x04, 0x0a, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x21, 0x73, 0x04, 0xff, 0xff, 0xa0, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x22, 0x0e, 0x00,
+ 0x02, 0x7a, 0x08, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x02, 0x7a, 0x0c, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x02, 0x7a, 0x0b, 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x02, 0x7a, 0x0d, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x02, 0x7a, 0x0a, 0x00, 0x00, 0xe1, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe2, 0x0f, 0x00,
+ 0x23, 0x76, 0x0c, 0x0c, 0x00, 0xec, 0x01, 0x00, 0x0b, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x0f, 0x00,
+ 0x02, 0x7a, 0x0f, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xc6, 0x0f, 0x00,
+ 0x23, 0x76, 0x0d, 0x0d, 0x00, 0xed, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x20, 0x7a, 0x00, 0x04, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x1f, 0x04,
+ 0x20, 0x7a, 0x01, 0x04, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x23, 0x7a, 0x00, 0x05, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x20, 0x7a, 0x02, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x01, 0x05, 0x00, 0x35, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x00, 0x06, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x23, 0x7a, 0x02, 0x05, 0x00, 0x39, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x01, 0x06, 0x00, 0x36, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x20, 0x72, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x02, 0x06, 0x00, 0x3a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x72, 0x03, 0x01, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xc8, 0x0f, 0x00,
+ 0x23, 0x72, 0x05, 0x02, 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0xca, 0x0f, 0x00,
+ 0x0b, 0x72, 0x00, 0x05, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf1, 0x03, 0x00, 0xd8, 0x0f, 0x00,
+ 0x08, 0x03, 0x05, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x22, 0x0e, 0x00,
+ 0x0b, 0x7a, 0x00, 0xff, 0x00, 0xf0, 0x01, 0x00, 0x00, 0xd0, 0xf1, 0x03, 0x00, 0xe2, 0x0f, 0x00,
+ 0x20, 0x72, 0x04, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x1f, 0x08,
+ 0x20, 0x72, 0x06, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x08,
+ 0x20, 0x7a, 0x01, 0x04, 0x00, 0x14, 0x02, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x20, 0x72, 0x07, 0x02, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe2, 0x0f, 0x00,
+ 0x09, 0x78, 0x05, 0x08, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x81, 0x07, 0x00, 0xe2, 0x0f, 0x00,
+ 0x23, 0x7a, 0x00, 0x06, 0x00, 0x15, 0x02, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xc6, 0x0f, 0x00,
+ 0x09, 0x78, 0x08, 0x05, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x81, 0x03, 0x00, 0xe2, 0x0f, 0x00,
+ 0x23, 0x7a, 0x00, 0x07, 0x00, 0x16, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x20, 0x7a, 0x05, 0x04, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe2, 0x0f, 0x00,
+ 0x02, 0x7a, 0x04, 0x00, 0x00, 0xe2, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x09, 0x72, 0x09, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x07, 0x00, 0xe2, 0x0f, 0x00,
+ 0x23, 0x7a, 0x06, 0x06, 0x00, 0x09, 0x02, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x21, 0x73, 0x00, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x22, 0x0e, 0x00,
+ 0x23, 0x76, 0x0f, 0x0f, 0x00, 0xee, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00,
+ 0x08, 0x73, 0x09, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x62, 0x0e, 0x00,
+ 0x23, 0x7a, 0x0a, 0x07, 0x00, 0x0a, 0x02, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0xca, 0x0f, 0x00,
+ 0x09, 0x72, 0x0a, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x07, 0x00, 0xc8, 0x0f, 0x00,
+ 0x0b, 0x72, 0x00, 0x0a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x40, 0xf3, 0x03, 0x00, 0xe2, 0x0f, 0x00,
+ 0x20, 0x72, 0x0b, 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x2f, 0x00,
+ 0x20, 0x7a, 0x04, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xc8, 0x1f, 0x00,
+ 0x08, 0x73, 0x0b, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x22, 0x0e, 0x00,
+ 0x20, 0x7a, 0x06, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x20, 0x7a, 0x08, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x20, 0x7a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x05, 0x01, 0x00, 0x21, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x23, 0x7a, 0x07, 0x01, 0x00, 0x25, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x23, 0x7a, 0x09, 0x01, 0x00, 0x29, 0x00, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x01, 0x01, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x00, 0x02, 0x00, 0x22, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x0f, 0x04,
+ 0x08, 0x78, 0x0b, 0x0b, 0x00, 0x00, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x1f, 0x00,
+ 0x23, 0x7a, 0x0e, 0x02, 0x00, 0x2e, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x01, 0x0a, 0x00, 0x1c, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x0f, 0x00,
+ 0x08, 0x72, 0x0b, 0x0b, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0xe2, 0x0f, 0x00,
+ 0x23, 0x7a, 0x04, 0x02, 0x00, 0x26, 0x00, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x23, 0x7a, 0x06, 0x02, 0x00, 0x2a, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x02, 0x0a, 0x00, 0x1d, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x23, 0x7a, 0x0a, 0x0a, 0x00, 0x1e, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x07, 0x01, 0x00, 0xe4, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x01, 0x03, 0x00, 0x27, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x04, 0x0b, 0x00, 0x20, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x23, 0x7a, 0x05, 0x0b, 0x00, 0x21, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x08, 0x02, 0x00, 0xe5, 0x01, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x0a, 0x0a, 0x00, 0xe6, 0x01, 0x00, 0x0f, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x0b, 0x0b, 0x00, 0x22, 0x02, 0x00, 0xff, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x02, 0x03, 0x00, 0x2b, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x04,
+ 0x23, 0x7a, 0x04, 0x04, 0x00, 0xe8, 0x01, 0x00, 0x07, 0x00, 0x01, 0x00, 0x00, 0xe2, 0x0f, 0x00,
+ 0x02, 0x7a, 0x07, 0x00, 0x00, 0xe7, 0x01, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0xe2, 0x0f, 0x00,
+ 0x23, 0x7a, 0x00, 0x03, 0x00, 0x23, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0xc4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x0e, 0x03, 0x00, 0x2f, 0x00, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x05, 0x05, 0x00, 0xe9, 0x01, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x23, 0x7a, 0x06, 0x0b, 0x00, 0xea, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00, 0x00, 0xe4, 0x0f, 0x00,
+ 0x22, 0x73, 0x00, 0xff, 0x00, 0x70, 0x00, 0x00, 0xff, 0x08, 0x00, 0x00, 0x00, 0xe8, 0x0f, 0x00,
+ 0x22, 0x73, 0x00, 0xff, 0x0e, 0x7c, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x0f, 0x00,
+ 0x22, 0x73, 0x00, 0xff, 0x04, 0x80, 0x02, 0x00, 0xff, 0x0c, 0x00, 0x00, 0x00, 0xe2, 0x0f, 0x00,
+ 0x4d, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0xea, 0x0f, 0x00,
+ 0x47, 0x79, 0x00, 0x00, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x83, 0x03, 0x00, 0xc0, 0x0f, 0x00,
+};
+
+/*
* r1481: shader-image cache filled from any push chunk that starts with a
* real SPH magic. The client's init push carries its VS/PS images as raw
* continuation chunks (first word 020a0481 / 000a1482) whose method
@@ -8434,6 +8545,43 @@ static void svc_gl_prog_apply_param(void)
&svc_gl_vs_len, svc_gl_vs_seen);
svc_gl_hex_parse(sema_gl_ps_hex, "ps-hex", svc_gl_ps,
&svc_gl_ps_len, svc_gl_ps_seen);
+ if (READ_ONCE(sema_gl_vs_img) && !svc_gl_vs_len) {
+ memcpy(svc_gl_vs, svc_gl_vs_img, sizeof(svc_gl_vs_img));
+ svc_gl_vs_len = (u32)sizeof(svc_gl_vs_img);
+ }
+}
+
+/*
+ * r1492: is a captured program image complete enough to deliver?
+ *
+ * The client's 0x180/0x1b0 upload runs carry a 128 B SPH followed by SASS.
+ * The push decoder reads a long entry page by page; when the image payload
+ * straddles a page whose continuation the ring mapping does not describe,
+ * the captured bytes are the SPH (in the first page) plus ZERO for the
+ * SASS tail. r1491 proved that shape on the beef VTG page: the shadow
+ * receipt read `020a0481 ...` at +0x900 and `code4=00000000` at +0x980,
+ * while the same page's PS and TESS images had real SASS. Delivering such
+ * an image overwrites the real program page with a header that has no
+ * code, so the VS executes NOPs and no vertex reaches the raster.
+ *
+ * Gate: SPH magic (SPH type 1=VTG or 2=PS in bits 4:0) and at least one
+ * nonzero word in the code region [0x80, min(len, 0x200)). A header-only
+ * image is rejected and the caller falls through to the known-good image
+ * path (sema_gl_vs_hex / ps_hex or the cached image).
+ */
+static bool svc_gl_img_code_ok(const u8 *d, u32 n)
+{
+ u32 w0, i;
+
+ if (!d || n < 0x90u)
+ return false;
+ w0 = get_unaligned_le32(d);
+ if ((w0 & 0x1fu) != 1u && (w0 & 0x1fu) != 2u)
+ return false;
+ for (i = 0x80u; i + 4u <= n && i < 0x200u; i += 4u)
+ if (get_unaligned_le32(d + i))
+ return true;
+ return false;
}
/*
@@ -10135,12 +10283,44 @@ static void svc_gl_flush(struct nv_vgpu_device *vgpu,
prs[n_recs].data,
(u32)sizeof(prs[n_recs].data));
+ /*
+ * r1492: a captured image whose
+ * SASS body is zero is the
+ * page-splice corruption, not a
+ * valid program; reject it so the
+ * authored image below (the real
+ * VS/PS bytes) can land instead.
+ */
+ if (got && !svc_gl_img_code_ok(
+ prs[n_recs].data,
+ rlen)) {
+ if (gsp_sema_dbg &&
+ svc_gl_prog_log < 64) {
+ svc_gl_prog_log++;
+ pr_info("sema-gl: real-upload REJECTED va=0x%llx len=%u first=%08x code4=%08x (SPH only; captured SASS body zero)\n",
+ svc_gl.progs[pi],
+ rlen,
+ get_unaligned_le32(
+ prs[n_recs].data),
+ rlen > 0x80u ?
+ get_unaligned_le32(
+ prs[n_recs].data +
+ 0x80u) :
+ 0u);
+ }
+ got = false;
+ rlen = 0;
+ }
if (!got && t != 5u && t != 0xffu) {
got = svc_grce_dst_sph(
0x020a0481u, 128u,
&rlen,
prs[n_recs].data,
(u32)sizeof(prs[n_recs].data));
+ if (got && !svc_gl_img_code_ok(
+ prs[n_recs].data,
+ rlen))
+ got = false;
if (!got &&
svc_gl_sph_cache_len[1]) {
rlen = min_t(u32,
@@ -10149,7 +10329,9 @@ static void svc_gl_flush(struct nv_vgpu_device *vgpu,
memcpy(prs[n_recs].data,
svc_gl_sph_cache[1],
rlen);
- got = true;
+ got = svc_gl_img_code_ok(
+ prs[n_recs].data,
+ rlen);
}
}
if (got) {
@@ -10240,12 +10422,37 @@ static void svc_gl_flush(struct nv_vgpu_device *vgpu,
if (svc_gl.up[uu].len < 128u)
continue;
if ((svc_gl.up[uu].dst_va &
- ~(u64)(SEMA_PAGE_SIZE - 1)) ==
+ ~(u64)(SEMA_PAGE_SIZE - 1)) !=
(svc_gl.progs[pi] &
- ~(u64)(SEMA_PAGE_SIZE - 1))) {
- real_up = true;
- break;
+ ~(u64)(SEMA_PAGE_SIZE - 1)))
+ continue;
+ /*
+ * r1492: same page, but a
+ * header-only payload is the
+ * page-splice corruption - do not
+ * let it suppress the authored
+ * real image.
+ */
+ if (!svc_gl_img_code_ok(
+ svc_gl.up[uu].data,
+ svc_gl.up[uu].len)) {
+ if (gsp_sema_dbg &&
+ svc_gl_prog_log < 64) {
+ svc_gl_prog_log++;
+ pr_info("sema-gl: real-upload page va=0x%llx len=%u code4=%08x rejected (authored image used)\n",
+ svc_gl.up[uu].dst_va,
+ svc_gl.up[uu].len,
+ svc_gl.up[uu].len >
+ 0x80u ?
+ get_unaligned_le32(
+ svc_gl.up[uu].data +
+ 0x80u) :
+ 0u);
+ }
+ continue;
}
+ real_up = true;
+ break;
}
if (real_up) {
if (gsp_sema_dbg &&
@@ -15150,16 +15357,84 @@ static u32 svc_gl_cb_hash(const u8 *p, u32 n)
return h;
}
+/*
+ * r1491: is the position block (c[0x0][0x80..0xbc], the 4x4 matrix the
+ * captured VS uses to turn the vertex into clip space) usable? A NaN/Inf
+ * word or an all-zero 16-word block means the source page is not the
+ * engine-written fixed constant buffer (or the matrix was never filled),
+ * and the draw would collapse every triangle regardless of the vertex
+ * fetch. Finite and not all-zero is the minimum credible shape.
+ */
+static bool svc_gl_cb_matrix_ok(const u8 *buf)
+{
+ u32 i, nz = 0, normal = 0;
+
+ for (i = 0; i < 16u; i++) {
+ u32 w = get_unaligned_le32(buf + 0x80u + i * 4u);
+ u32 exp = (w >> 23) & 0xffu;
+
+ if (exp == 0xffu)
+ return false;
+ if (!(w & 0x7fffffffu))
+ continue;
+ nz++;
+ /*
+ * r1492: a method-stream page mis-resolved for the CB
+ * answers with headers/payload words whose "floats" are
+ * zero/denormal/tiny (0x2001xxxx -> exp 0x40). A real
+ * transform row has normal-scale components. Requiring four
+ * normal-magnitude words rejects the method pages that made
+ * r1492 accept a garbage matrix (`00000053 80000585
+ * 20010d2a ... ok=1`).
+ */
+ if (exp >= 0x70u && exp <= 0x8eu)
+ normal++;
+ }
+ return nz != 0u && normal >= 4u;
+}
+
+static void svc_gl_cb_dump_matrix(const u8 *buf, const char *src, u64 pa,
+ u32 ap, int ssrc)
+{
+ u32 i, w[16];
+
+ for (i = 0; i < 16u; i++)
+ w[i] = get_unaligned_le32(buf + 0x80u + i * 4u);
+ pr_info("vgsp-sema: sema-gl: cb-matrix src=%s pa=0x%llx ap=%u ssrc=%d m[0x80..0xbc]=%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x ok=%u\n",
+ src, pa, ap, ssrc, w[0], w[1], w[2], w[3], w[4], w[5],
+ w[6], w[7], w[8], w[9], w[10], w[11], w[12], w[13], w[14],
+ w[15], svc_gl_cb_matrix_ok(buf));
+ pr_info("vgsp-sema: sema-gl: cb-const src=%s c[0x2a0..0x2a8]=%08x %08x %08x c[0x780..0x7c8]=%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x c[0x820..0x828]=%08x %08x %08x c[0x850..0x858]=%08x %08x %08x c[0x870..0x888]=%08x %08x %08x %08x %08x %08x %08x\n",
+ src,
+ get_unaligned_le32(buf + 0x2a0), get_unaligned_le32(buf + 0x2a4),
+ get_unaligned_le32(buf + 0x2a8),
+ get_unaligned_le32(buf + 0x780), get_unaligned_le32(buf + 0x784),
+ get_unaligned_le32(buf + 0x788), get_unaligned_le32(buf + 0x78c),
+ get_unaligned_le32(buf + 0x790), get_unaligned_le32(buf + 0x794),
+ get_unaligned_le32(buf + 0x798), get_unaligned_le32(buf + 0x79c),
+ get_unaligned_le32(buf + 0x7a0), get_unaligned_le32(buf + 0x7a4),
+ get_unaligned_le32(buf + 0x7a8), get_unaligned_le32(buf + 0x7c0),
+ get_unaligned_le32(buf + 0x7c4), get_unaligned_le32(buf + 0x7c8),
+ get_unaligned_le32(buf + 0x820), get_unaligned_le32(buf + 0x824),
+ get_unaligned_le32(buf + 0x828),
+ get_unaligned_le32(buf + 0x850), get_unaligned_le32(buf + 0x854),
+ get_unaligned_le32(buf + 0x858),
+ get_unaligned_le32(buf + 0x870), get_unaligned_le32(buf + 0x874),
+ get_unaligned_le32(buf + 0x878),
+ get_unaligned_le32(buf + 0x880), get_unaligned_le32(buf + 0x884),
+ get_unaligned_le32(buf + 0x888));
+}
+
static void svc_gl_cb_copy(struct nv_vgpu_device *vgpu, u32 h_object)
{
/* Static: 4 KB is too much for the kernel stack; this runs on the
* single service thread (same reason as the static arrays in
* svc_gl_flush and svc_decode_stream). */
static u8 buf[SEMA_PAGE_SIZE];
- u64 src_va, pa = 0;
+ u64 src_va, pa = 0, hpa = 0;
u32 ap = 0, val, hash;
const char *src = "resolve";
- int rc;
+ int rc, ssrc = 0;
if (!sema_gl_cb_copy_to)
return;
@@ -15176,65 +15451,141 @@ static void svc_gl_cb_copy(struct nv_vgpu_device *vgpu, u32 h_object)
return;
src_va = (u64)val << 8;
}
- rc = svc_resolve_va(vgpu, src_va, &pa, &ap);
- if (rc) {
- /* Fallback 1: the trusted walk svc_gl_flush uses for the
- * program page. */
- rc = svc_read_va_trusted(vgpu, src_va, buf, sizeof(buf));
- if (!rc) {
- src = "trusted";
+ /*
+ * r1491: the fixed constant buffer is ENGINE-written (the driver
+ * publishes its base through SET_MME_SHADOW_SCRATCH(FIXED_CONSTANT_
+ * BUFFER), then VPC constant methods and the fixed-CB selector make
+ * the GPU fill it). Its content therefore lives in the page the GR
+ * engine reads: a guest-RAM GPA (SYS). The emulated BAR1 vidmem
+ * shadow only holds guest-CPU writes through the aperture, so
+ * reading a FB-resolved fixed CB there returns unrelated vidmem -
+ * r1490 read `09037223 00000004`, r1482 oscillated between a float
+ * row, method words and zeros. Resolve the page the way the engine
+ * does first: this channel's own VAS, then the GR relocation
+ * resolver (ledger + VAS walk + verified HPA). Only a SYS answer is
+ * content-valid; an FB answer falls through to the walk paths, and
+ * the FB shadow read is the last resort (and marks the matrix
+ * untrusted).
+ */
+ if (!svc_chanvas_lookup(vgpu, src_va, &pa, &ap)) {
+ ssrc = 1;
+ src = "chanvas";
+ if (ap == SVC_APERTURE_SYS &&
+ !svc_read_ap(vgpu, pa, SVC_APERTURE_SYS, buf,
+ sizeof(buf)))
goto have;
+ }
+ /*
+ * r1492: walk every registered VAS before the GR ledger. The
+ * landing table (which gr_reloc_resolve prefers for VAs above
+ * SVC_VAS_FLOOR) is fed by our own launches and can answer with a
+ * re-used VA's page; the page tables are the mapping truth.
+ */
+ if (!svc_walk_vaspaces(vgpu,
+ src_va & ~(u64)(SEMA_PAGE_SIZE - 1),
+ &pa, &ap)) {
+ pa += src_va & (SEMA_PAGE_SIZE - 1u);
+ ssrc = 8;
+ src = "vaswalk";
+ if (ap == SVC_APERTURE_SYS &&
+ !svc_read_ap(vgpu, pa, SVC_APERTURE_SYS, buf,
+ sizeof(buf)))
+ goto have;
+ }
+ {
+ struct gsp_sema_gr_reloc r;
+
+ if (!gsp_sema_gr_reloc_resolve(src_va, &r)) {
+ pa = r.pa;
+ ap = r.ap;
+ hpa = r.hpa;
+ ssrc = 2;
+ src = (r.ap == SVC_APERTURE_FB) ? "gr-fb" : "gr-sys";
+ if (r.ap == SVC_APERTURE_SYS &&
+ !svc_read_ap(vgpu, pa, SVC_APERTURE_SYS, buf,
+ sizeof(buf)))
+ goto have;
}
- /* Fallback 2: the general lookup (adds the vidmem window
- * convention). */
- rc = svc_read_va(vgpu, src_va, buf, sizeof(buf));
- if (!rc) {
- src = "lookup";
+ }
+ rc = svc_resolve_va(vgpu, src_va, &pa, &ap);
+ if (!rc && ap == SVC_APERTURE_SYS &&
+ !svc_read_ap(vgpu, pa, SVC_APERTURE_SYS, buf, sizeof(buf))) {
+ ssrc = 3;
+ src = "resolve-sys";
+ goto have;
+ }
+ if (!rc) {
+ /* An FB resolution is only valid for content the guest CPU
+ * writes through the aperture; use it but flag it. */
+ if (!svc_read_ap(vgpu, pa, ap, buf, sizeof(buf))) {
+ ssrc = 4;
+ src = "resolve-fb";
goto have;
}
- /*
- * r1476: the client's fixed-CB VA is a GPU/vidmem VA the
- * service cannot walk (resolve -2 even through the trusted
- * and general fallbacks). Rather than leave the VS reading
- * screen data, author a synthetic identity MVP at the
- * position block the VS reads (c[0x0][0x80..0xbc], one
- * 4x4 row-major matrix). The vertices then pass through in
- * model space; the viewport prelude maps NDC to the RT. This
- * is a controlled positive control for the raster path: if
- * pixels appear, the constant CONTENT is the only remaining
- * unknown; if not, the raster/clip path is still wrong.
- */
+ }
+ /* Fallback: the trusted walk svc_gl_flush uses for the program page. */
+ if (!svc_read_va_trusted(vgpu, src_va, buf, sizeof(buf))) {
+ ssrc = 5;
+ src = "trusted";
+ goto have;
+ }
+ /* Fallback: the general lookup (adds the vidmem window convention). */
+ if (!svc_read_va(vgpu, src_va, buf, sizeof(buf))) {
+ ssrc = 6;
+ src = "lookup";
+ goto have;
+ }
+ /*
+ * r1476: nothing resolved the client's fixed-CB VA. Rather than
+ * leave the VS reading screen data, author a synthetic identity MVP
+ * at the position block the VS reads (c[0x0][0x80..0xbc], one 4x4
+ * row-major matrix). The vertices then pass through in model space;
+ * the viewport prelude maps NDC to the RT. This is a controlled
+ * positive control for the raster path: if pixels appear, the
+ * constant CONTENT is the only remaining unknown; if not, the
+ * raster/clip path is still wrong.
+ */
+ memset(buf, 0, sizeof(buf));
+ put_unaligned_le32(0x3f800000u, buf + 0x80); /* m00 */
+ put_unaligned_le32(0x3f800000u, buf + 0x94); /* m11 */
+ put_unaligned_le32(0x3f800000u, buf + 0xa8); /* m22 */
+ put_unaligned_le32(0x3f800000u, buf + 0xbc); /* m33 */
+ src = "synthetic-id";
+ ssrc = 7;
+ goto have;
+have:
+ /*
+ * r1491: a source whose 0x80 block is not a credible matrix would
+ * still collapse every vertex. Only a SYS (engine-page) read is
+ * trusted; an FB-shadow read is by construction not the engine's
+ * page, so author the identity positive control there too.
+ */
+ if ((ssrc == 4 || ssrc == 5 || ssrc == 6 || ssrc == 7) ||
+ !svc_gl_cb_matrix_ok(buf)) {
memset(buf, 0, sizeof(buf));
put_unaligned_le32(0x3f800000u, buf + 0x80); /* m00 */
put_unaligned_le32(0x3f800000u, buf + 0x94); /* m11 */
put_unaligned_le32(0x3f800000u, buf + 0xa8); /* m22 */
put_unaligned_le32(0x3f800000u, buf + 0xbc); /* m33 */
src = "synthetic-id";
- goto have;
}
- if (svc_read_ap(vgpu, pa, ap, buf, sizeof(buf))) {
- if (svc_gl_cb_copy_log < 8u) {
- svc_gl_cb_copy_log++;
- pr_info("vgsp-sema: sema-gl: cb-copy src=0x%llx dst=0x%llx resolve=0 ap=%u read failed\n",
- src_va, sema_gl_cb_copy_to, ap);
- }
- return;
- }
-have:
hash = svc_gl_cb_hash(buf, sizeof(buf));
if (svc_gl_cb_copy_h == h_object && svc_gl_cb_copy_val == val &&
svc_gl_cb_copy_hash == hash)
return;
rc = svc_grce_inline_write(vgpu, sema_gl_cb_copy_to, buf, sizeof(buf),
h_object);
- if (svc_gl_cb_copy_log < 8u) {
+ if (svc_gl_cb_copy_log < 24u) {
u32 w0, w1;
memcpy(&w0, buf, 4);
memcpy(&w1, buf + 4, 4);
svc_gl_cb_copy_log++;
- pr_info("vgsp-sema: sema-gl: cb-copy src=0x%llx dst=0x%llx resolve=%d ap=%u first=%08x %08x src=%s write=%d (fixed-CB page -> forced seed page)\n",
- src_va, sema_gl_cb_copy_to, 0, ap, w0, w1, src, rc);
+ pr_info("vgsp-sema: sema-gl: cb-copy src=0x%llx dst=0x%llx pa=0x%llx ap=%u hpa=0x%llx ssrc=%d first=%08x %08x src=%s write=%d (fixed-CB page -> forced seed page)\n",
+ src_va, sema_gl_cb_copy_to, pa, ap, hpa, ssrc, w0, w1,
+ src, rc);
+ if (svc_gl_cb_copy_log <= 4u)
+ svc_gl_cb_dump_matrix(buf, src, pa, ap, ssrc);
}
if (!rc) {
svc_gl_cb_copy_h = h_object;