summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-12 01:38:02 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-12 01:46:11 -0400
commita5e57a960dfb11abf50e28487f8b11d6b88aadaf (patch)
tree3fbb25bc6a2d496d31ec936d0c675d04afdb25bd /kernel
parent5802137750f45d64d3c4ee4f2de6b825b28f163a (diff)
downloadopen-iov-a5e57a960dfb11abf50e28487f8b11d6b88aadaf.tar.gz
open-iov-a5e57a960dfb11abf50e28487f8b11d6b88aadaf.zip
vgsp-sema: discover GR data candidates from the fresh inline param block (second-client fix)
Second-client launches scanned a stale/reused guest param page that still held the FIRST client's device VAs: zero new candidates resolved, nothing was relocated, and the engine executed with unrelocated guest pointers (r97 evidence: client#1 '15 candidate ptrs, 100 pages resolved' and win0 param 160=110400; client#2 '12 candidates, 1 page' with 160=75552ec00000 unrelocated). The driver-authored inline param block is captured from the pushbuffer at request time, so scanning it makes pointer discovery independent of guest-page reuse timing. Adds svc_gr_scan_cand()/ svc_gr_scan_inline() and the DIAG win0/guest-param proof line. Client #1 stays green (4 cycles); the remaining second-client stall is the pool semaphore residue (see next commit).
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c40
-rw-r--r--kernel/gsp_sema_service.c57
2 files changed, 97 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 47e3bd0..f083c99 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -17432,6 +17432,46 @@ gr_page_unmapped:
}
if (gsp_phys_rmcall_gr_gpc_mmu_init_value())
gsp_phys_rmcall_gr_gpc_mmu_init(bar0);
+ /*
+ * m143 DIAGNOSTIC (second-client launch-state divergence): dump the
+ * exact param page the FE/SM will read (win0 slot 0, the QMD bank-0
+ * target) and the guest param page at the three JIT parameter slots,
+ * right before the doorbell. The JIT reads a@0x160/b@0x168/c@0x170
+ * and n@0x178 (verified with ptxas -arch=sm_75). If the win0 copy is
+ * correct here but the engine still stores to the wrong relocated
+ * window, the divergence is engine-side (a stale mapping), not the
+ * relaunched page content.
+ */
+ if (boot_stage.rmcall_gr_shadow_win0.pages) {
+ const u8 *wp = gsp_phys_chunk_page_va(
+ &boot_stage.rmcall_gr_shadow_win0, 0);
+
+ if (wp)
+ pr_info("vgsp-gr: DIAG win0[0] 160=%llx 168=%llx 170=%llx 178=%llx\n",
+ (u64)get_unaligned_le64(wp + 0x160),
+ (u64)get_unaligned_le64(wp + 0x168),
+ (u64)get_unaligned_le64(wp + 0x170),
+ (u64)get_unaligned_le64(wp + 0x178));
+ }
+ {
+ u32 pi;
+
+ for (pi = 0; pi < req->n_pages; pi++) {
+ const u8 *gp;
+
+ if (req->pages[pi].qmd_word != 32u ||
+ !req->pages[pi].hpa)
+ continue;
+ gp = (const u8 *)__va(req->pages[pi].hpa);
+ pr_info("vgsp-gr: DIAG guest-param pa=0x%llx 160=%llx 168=%llx 170=%llx 178=%llx\n",
+ req->pages[pi].hpa,
+ (u64)get_unaligned_le64(gp + 0x160),
+ (u64)get_unaligned_le64(gp + 0x168),
+ (u64)get_unaligned_le64(gp + 0x170),
+ (u64)get_unaligned_le64(gp + 0x178));
+ break;
+ }
+ }
pr_info("vgsp-gr: GR LAUNCH submitted h=0x%x push=0x%llx len=%u pages=%u shadow=%u qmd_va=0x%llx slot=%u words=%u prelude=%d qmdvirt=%d token=0x%x; polling qmd_rel=%u ch_rel=0x%08x (<=%u ms)%s\n",
req->h_object, req->push_va, req->push_len, req->n_pages,
n_shadow, req->qmd_va, sub.slot, words,
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index ec269c5..7d690ab 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -12129,6 +12129,56 @@ static bool svc_gr_page_inline_covers(u64 page)
static u32 svc_gr_data_log; /* m142: bounded per-page attribution log */
+/*
+ * m144 (second-client launch-state divergence): collect device-VA-shaped
+ * candidate pointers from the bytes the ENGINE will actually execute.
+ *
+ * The guest page read through the operand HPA can be STALE across a session
+ * boundary: the guest reuses the previous client's physical page for the new
+ * client's parameter/bank page, and at scan time that page can still hold the
+ * previous client's device VAs (observed r97: the second client's data fill
+ * read the first client's VAs, resolved zero pages, relocated nothing, and
+ * the engine then executed the kernel against the ORIGINAL unrelocated
+ * pointers - the win0 param page kept 0x75552ec00000 instead of 0x110000).
+ * The driver ALSO writes the kernel parameter block inline; those bytes are
+ * captured fresh from the launch pushbuffer at request time and are overlaid
+ * onto the shadow page by the backend. Scan them too (the scan is by value,
+ * so the in-page offset of an inline record does not matter) so pointer
+ * discovery is independent of guest-page reuse timing.
+ */
+static void svc_gr_scan_cand(u64 *wins, u32 *n_cand, const u8 *data, u32 bytes)
+{
+ u32 k;
+
+ for (k = 0; k + 8 <= bytes; k += 8) {
+ u64 v = get_unaligned_le64(data + k);
+ u64 wv;
+ u32 w;
+
+ if (v < 0x10000000ULL || v >= (1ULL << 47) || (v & 3))
+ continue;
+ wv = v & ~(u64)(SEMA_PAGE_SIZE - 1);
+ for (w = 0; w < *n_cand; w++)
+ if (wins[w] == wv)
+ break;
+ if (w == *n_cand && *n_cand < 16u)
+ wins[(*n_cand)++] = wv;
+ }
+}
+
+static void svc_gr_scan_inline(u64 *wins, u32 *n_cand, u64 page_va)
+{
+ u32 j;
+
+ for (j = 0; j < svc_gr_cand.n_inline && j < SVC_GR_INLINE_MAX; j++) {
+ const struct svc_gr_inline *inl = &svc_gr_cand.inline_recs[j];
+
+ if ((inl->dst_va & ~(u64)(SEMA_PAGE_SIZE - 1)) != page_va)
+ continue;
+ svc_gr_scan_cand(wins, n_cand, inl->data, inl->len);
+ }
+}
+
static void svc_gr_data_fill(struct nv_vgpu_device *vgpu)
{
u64 wins[16];
@@ -12185,6 +12235,10 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu)
if (w == n_cand && n_cand < ARRAY_SIZE(wins))
wins[n_cand++] = wv;
}
+ /* m144: also scan the fresh inline-captured parameter block,
+ * so a reused/stale guest page cannot hide the kernel's device
+ * pointers. */
+ svc_gr_scan_inline(wins, &n_cand, pp->va);
}
for (i = 0; i < svc_fwd_req.gr_n_pages; i++) {
const struct svc_gr_page *pp = &svc_fwd_req.gr_pages[i];
@@ -12217,6 +12271,9 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu)
if (w == n_cand && n_cand < ARRAY_SIZE(wins))
wins[n_cand++] = wv;
}
+ /* m144: bank pages carry their own pointers too; scan the fresh
+ * inline-captured bytes as well (see svc_gr_scan_inline). */
+ svc_gr_scan_inline(wins, &n_cand, pp->va);
}
/* m110: one contiguous run of pages per candidate pointer, relocated
* into the engine-walkable main-PT window (0x110000 onward, fresh