summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-31 07:21:28 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-31 07:21:28 -0400
commitf8f0a86a07949f913e546de4459c779a9ccbc3f3 (patch)
tree01d80fcfa750aa7bfd49aa3ea031c9aca75b3d00 /kernel/gsp_sema_service.c
parentdf072897fef8421c7f41d7a9ebc9f3415210b402 (diff)
downloadopen-iov-f8f0a86a07949f913e546de4459c779a9ccbc3f3.tar.gz
open-iov-f8f0a86a07949f913e546de4459c779a9ccbc3f3.zip
vgsp+diag: SA-RAM table captured unbounded (entry[64], sema-mme-sa log), surf geometry accessor + completeness recs, fill seeds RT candidate 0 full span (<=1024 pages, completeness only on fully-resolved run); MME slot stub (called-but-uncaptured slots end-noop IR 0xC0, sema_gl_mme_sa_stub=1), reloc prefers tracked rec bounce VA; pin family += 0x4200000 - 0x238c wall root-caused (capture truncated buffer full=28 words=512, SA[0x22]=0 jump IR 0; sim proves slot-0 emits EMIT 0x238c=0x20020); fixes never executed (setup-push read lost, unreadable=1 first8=00040000 00001000); next: trustworthy pagemap resolve or accept ipin first-chunk - SESSION 153 r1117-r1120
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c191
1 files changed, 191 insertions, 0 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 4d32caa..856947f 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -14052,6 +14052,45 @@ module_param_named(sema_mme_prelude_cap, svc_mme_prelude_flag, uint, 0644);
MODULE_PARM_DESC(sema_mme_prelude_cap,
"Capture the client's MME context-setup method runs (0x114..0x124, 0x234, 0x550..0x568, 0x3400..0x34fc) from trusted beef pushes for the GR launch builder's one-time preplay (default 1)");
+/*
+ * SESSION 153-CONTINUED-63: the MME START-ADDRESS RAM table (macro slot ->
+ * IR instruction address), captured unbounded by the 512-word prelude
+ * buffer. The r1116 0x238c wall proved the replay's SA table was
+ * incomplete (the capture buffer filled with the first 11 macros' code and
+ * 28 further setup runs - the remaining slots - never entered the prelude):
+ * the window's CALL_MME_MACRO(0x22) then read SA[0x22] = 0 on the fresh
+ * context, the MME jumped to IR 0 (the slot-0 macro, simulating with the
+ * caller's args emits LOAD_CONSTANT_BUFFER_OFFSET <- 0x20020; verified
+ * with the offline MME64 simulator), and the class error poisoned the
+ * lane. The builder uses this table to complete the SA RAM it replays and
+ * to stub every called-but-unknown slot with a harmless end-noop.
+ */
+static u64 svc_mme_sa_present;
+static u32 svc_mme_sa_entry[64];
+static u32 svc_mme_sa_log;
+
+u64 gsp_sema_mme_sa_get(u32 *entries, u32 n)
+{
+ u32 i;
+
+ if (entries)
+ for (i = 0; i < n && i < 64u; i++)
+ entries[i] = svc_mme_sa_entry[i];
+ return READ_ONCE(svc_mme_sa_present);
+}
+
+static void svc_mme_sa_record(u32 slot, u32 entry)
+{
+ if (slot >= 64u)
+ return;
+ if (!(svc_mme_sa_present & (1ull << slot)) && svc_mme_sa_log < 64) {
+ svc_mme_sa_log++;
+ pr_info("sema-mme-sa: slot[%u] entry=0x%x\n", slot, entry);
+ }
+ svc_mme_sa_entry[slot] = entry;
+ svc_mme_sa_present |= 1ull << slot;
+}
+
static bool svc_mme_setup_run_addr(u32 addr)
{
return (addr >= 0x114u && addr <= 0x124u) || addr == 0x234u ||
@@ -14107,6 +14146,25 @@ static void svc_mme_prelude_capture(const u8 *buf, u32 len, u64 push_va,
break;
span = 1u + cnt;
}
+ /*
+ * SESSION 153-CONTINUED-63: record the START-ADDRESS RAM
+ * pairs independent of the prelude buffer's 512-word bound
+ * (see svc_mme_sa_present). The client's LoadMmeStartAddress
+ * Ram pair run is INC 0x11c with [slot, IR-address] pairs; a
+ * second run for the same slots overwrites (last wins), the
+ * same order the engine would see.
+ */
+ if (addr == 0x11cu && cnt >= 2u && span > 1u) {
+ u32 k;
+
+ for (k = 0; k + 1u < cnt; k += 2u) {
+ u32 sv, ev;
+
+ memcpy(&sv, buf + off + 4u + 4u * k, 4);
+ memcpy(&ev, buf + off + 8u + 4u * k, 4);
+ svc_mme_sa_record(sv, ev);
+ }
+ }
if (!svc_mme_setup_run_addr(addr)) {
off += span * 4u;
continue;
@@ -14396,6 +14454,15 @@ static u32 svc_surf_pre_gen;
static u64 svc_surf_pre_sig;
static u32 svc_surf_pre_log;
static u32 svc_surf_pre_flag = 1;
+/*
+ * SESSION 153-CONTINUED-63: the captured colour target's geometry, for the
+ * fill's render-target tracking (see svc_gr_data_fill and
+ * gsp_sema_gr_surf_recs): the fill seeds the surface base VA as a tracked
+ * data candidate so the engine's stores into the target become a retire
+ * witness and the copy-out ships them back to the guest's own pages.
+ */
+static u64 svc_surf_pre_va;
+static u32 svc_surf_pre_npages;
module_param_named(sema_surf_prelude_cap, svc_surf_pre_flag, uint, 0644);
MODULE_PARM_DESC(sema_surf_prelude_cap,
"Capture the last C597 colour-target bind (INC 0x800+j*0x40, fmt 0xe6) from trusted pushes so the GR launch builder can replay it ahead of 3D windows that carry no render target (default 1)");
@@ -14409,6 +14476,19 @@ const u32 *gsp_sema_surf_prelude_get(u32 *n, u32 *gen)
return svc_surf_pre_buf;
}
+bool gsp_sema_surf_va_get(u64 *va, u32 *npages)
+{
+ u32 n = READ_ONCE(svc_surf_pre_npages);
+
+ if (!n)
+ return false;
+ if (va)
+ *va = svc_surf_pre_va;
+ if (npages)
+ *npages = n;
+ return true;
+}
+
static void svc_surf_prelude_capture(const u8 *buf, u32 len)
{
u32 off = 0;
@@ -14458,6 +14538,8 @@ static void svc_surf_prelude_capture(const u8 *buf, u32 len)
memcpy(&svc_surf_pre_buf[k], buf + off + 4u * k, 4);
WRITE_ONCE(svc_surf_pre_n, n);
svc_surf_pre_sig = sig;
+ svc_surf_pre_va = va;
+ WRITE_ONCE(svc_surf_pre_npages, (u32)npages);
WRITE_ONCE(svc_surf_pre_gen, svc_surf_pre_gen + 1);
if (svc_surf_pre_log < 8) {
svc_surf_pre_log++;
@@ -29499,6 +29581,34 @@ static bool svc_gr_page_inline_covers(u64 page)
*/
#define SVC_GR_DATA_BOUNCE_MAX (GSP_PHYS_RMCALL_GR_DATA_BOUNCE_PAGES / 2u)
#define SVC_GR_DATA_BOUNCE_MAX_OLD 205u
+/*
+ * SESSION 153-CONTINUED-63: render-target page tracking (see
+ * gsp_sema_surf_va_get above). The captured colour target is seeded as a
+ * tracked data candidate so (a) GR-DEC n_data >= 1, (b) the retire wait
+ * counts the engine's stores into the target ("N/N pages changed") and
+ * (c) the copy-out ships the changed pages back to the guest's own screen
+ * pages. Bounded to one full 1280x720 RGB surface plus slack; the
+ * completeness record (va + n) arms the booter's rec-over-alias operand
+ * preference only when EVERY page resolved, so a partial span can never
+ * hand the engine a base pointer walking past the tracked run.
+ */
+#define SVC_GR_SURF_TRACK_MAX 1024u
+static u64 svc_gr_surf_rec_va;
+static u32 svc_gr_surf_rec_n;
+static u32 svc_gr_surf_rec_ok;
+static u32 svc_gr_surf_rec_log;
+
+bool gsp_sema_gr_surf_recs(u64 *va, u32 *n)
+{
+ if (!READ_ONCE(svc_gr_surf_rec_ok))
+ return false;
+ if (va)
+ *va = svc_gr_surf_rec_va;
+ if (n)
+ *n = svc_gr_surf_rec_n;
+ return true;
+}
+
static u32 svc_gr_data_log; /* m142: bounded per-page attribution log */
static u32 svc_gr_src_log; /* m150: bounded per-candidate source log */
@@ -30387,6 +30497,33 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
*/
n_cand = 0;
/*
+ * SESSION 153-CONTINUED-63: the captured colour target (the surface
+ * the replayed draw rasterizes into) becomes a tracked data
+ * candidate FIRST, so its pages are in the launch's data set even
+ * when the window/content scans fill every other slot (the beef
+ * windows' 24 scan candidates are all unresolvable junk). Odd: the
+ * copy-in stages the guest page into the bounce, the engine's
+ * stores land in the bounce, the retire wait sees them (GR-DEC
+ * n_data>=1 -> "N/N pages changed") and the copy-out writes the
+ * changed pages back to the guest's own pages. Completeness is
+ * recorded for the booter's rec-over-alias preference.
+ */
+ u64 surf_cand_va = 0;
+ u32 surf_cand_span = 0;
+ bool surf_cand_used = false;
+
+ WRITE_ONCE(svc_gr_surf_rec_ok, 0);
+ if (gsp_sema_surf_va_get(&surf_cand_va, &surf_cand_span)) {
+ if (surf_cand_span > SVC_GR_SURF_TRACK_MAX)
+ surf_cand_span = SVC_GR_SURF_TRACK_MAX;
+ if (surf_cand_va && !(surf_cand_va & (SEMA_PAGE_SIZE - 1)) &&
+ surf_cand_span && n_cand < SVC_GR_CAND_MAX) {
+ wins[n_cand] = surf_cand_va;
+ is_arg[n_cand] = false;
+ n_cand++;
+ }
+ }
+ /*
* m121: kernel-argument pointers first. The launched kernel's device
* pointers live in the param page (qmd_word 32, c[0x0]) at byte
* offsets >= 0x150 (m120: mail_kernel out@0x160, msg@0x168; vadd
@@ -30777,6 +30914,18 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
continue;
}
span = (base >= 0x40000000000ULL) ? per_ptr : 1u;
+ /*
+ * SESSION 153-CONTINUED-63: the render-target candidate keeps
+ * its full surface span (it is a low VA, so the generic span
+ * rule above would give it ONE page and the engine's raster
+ * walk would leave the tracked run at the first page
+ * crossing). surf_cand_used marks the pass so the tail can
+ * record completeness only for the run that actually filled.
+ */
+ if (surf_cand_va && base == surf_cand_va) {
+ span = surf_cand_span;
+ surf_cand_used = true;
+ }
if (is_arg[w] && base >= 0x40000000000ULL)
n_arg_hi++;
@@ -30958,6 +31107,19 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
svc_log_stalled_va(va);
if (is_arg[w])
svc_fwd_req.gr_arg_partial = true;
+ /*
+ * SESSION 153-CONTINUED-63: a
+ * render-target page that does
+ * not resolve must NOT hold
+ * the launch (the target is
+ * an output, not an operand;
+ * its alias fallback keeps
+ * today's behaviour), and the
+ * broken span must not be
+ * recorded as complete.
+ */
+ if (surf_cand_va && wins[w] == surf_cand_va)
+ break;
if (dropped_pages < 4) {
drop_va[dropped_pages] = va;
drop_kind[dropped_pages] =
@@ -31180,6 +31342,35 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
(n_arg_hi > 0 && n_arg_hi_res == 0);
svc_fwd_req.gr_dropped = dropped_pages;
/*
+ * SESSION 153-CONTINUED-63: record the render-target tracking run -
+ * only when the pass actually seeded it AND every requested page
+ * produced a data rec contiguous from the base (the booter then
+ * rewrites the target's operand pair to the bounce base; a partial
+ * run falls back to the identity alias so the engine can never walk
+ * past the tracked pages).
+ */
+ if (surf_cand_used) {
+ u32 hit = 0;
+
+ for (i = 0; i < svc_fwd_req.gr_n_data; i++) {
+ u64 rva = svc_fwd_req.gr_data[i].va;
+
+ if (rva >= surf_cand_va &&
+ rva < surf_cand_va +
+ ((u64)surf_cand_span << 12))
+ hit++;
+ }
+ if (hit == surf_cand_span) {
+ svc_gr_surf_rec_va = surf_cand_va;
+ svc_gr_surf_rec_n = surf_cand_span;
+ WRITE_ONCE(svc_gr_surf_rec_ok, 1);
+ } else if (svc_gr_surf_rec_log < 16) {
+ svc_gr_surf_rec_log++;
+ pr_info("vgsp-sema: surf-rec incomplete va=0x%llx want=%u got=%u (target falls back to the identity alias)\n",
+ surf_cand_va, surf_cand_span, hit);
+ }
+ }
+ /*
* GRFIX FIX1e (r215): gsp_phys_gr_fill_hold is the master gate.
* Default 0 = LOG-ONLY: the fill NEVER holds on dropped pages - the
* stalled verdict keeps only the historical pre-8b058884 aggregate