diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-12 01:38:02 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-12 01:46:11 -0400 |
| commit | a7263b28de7e4c35cccda910a806e4c4db15786b (patch) | |
| tree | 90920d290618890b9179039b56fad77caf369b02 | |
| parent | 864b0ab4b74811282546bf9143a6379aac628839 (diff) | |
| download | open-iov-a7263b28de7e4c35cccda910a806e4c4db15786b.tar.gz open-iov-a7263b28de7e4c35cccda910a806e4c4db15786b.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).
| -rw-r--r-- | kernel/gsp_phys_booter.c | 40 | ||||
| -rw-r--r-- | kernel/gsp_sema_service.c | 57 |
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 |
