summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-26 17:05:09 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-26 17:05:09 -0400
commit5c0fcc21c09a1fef22d2c1cd1277ad1d211826ac (patch)
tree751d2308caa33ea738ac7f71c4d4eb25769671c0
parent9cbae5ab817aa95445c79f6d7a7ff7de754c6319 (diff)
downloadopen-iov-5c0fcc21c09a1fef22d2c1cd1277ad1d211826ac.tar.gz
open-iov-5c0fcc21c09a1fef22d2c1cd1277ad1d211826ac.zip
vgsp-sema: SESSION 140 the n_data wiring - QMD-page note, qmd-ptr candidate seed, pin-aware scan reads
Three corrections that take the GR fill from 'no candidates' to the launch's real pointer set: 1. Note the QMD page itself into the request's page list (word 34) so the 32..48-even bank scan covers it - the pointer VALUES live inside the QMD (r790: word 34 = 0xdff0febc00) and were never scanned. 2. Seed the fill's candidate set directly from the launch's own QMD pointer pairs (gr_qmd words 34..47, decoded from the push's inline-QMD run): r793 'sema-gr: qmd-ptr seed va=0xdff0feb000 (word 34)' - the values need no page scan (the pages' shadows read empty; the invisible -vidmem-write class). 3. Read the scanned pages pin-aware (svc_read_va first, host mapping of pp->pa as fallback): the push-buffer discovery's pinned staging copy holds the content the decode reads; a raw mapping of the vidmem pa sees zeros. Verified r793/r794: candidates now appear (fill cand n=1 with the QMD window page seeded); the page is correctly classified launch-internal by the R3 hygiene filter (n_data stays 0 - nothing external to relocate for this launch). With the r564 degenerate-set guard bypassed (min_data=0), the forward ENTERS the backend and oopses in gsp_phys_backend_guest_gr_submit+0x4394 ('Oops: 0000 [#2]', workqueue gsp-phys-work svc_fwd_work_fn, NULL-base table walk CR2=0x1e93c R14=0) - the empty-set path needs that guard before min_data=0 can be used. This launch's QMD declares exactly one pointer pair, and it names its own QMD window: a launch with no external data is legitimate and the refusal class must not treat it as degenerate.
-rw-r--r--kernel/gsp_sema_service.c147
1 files changed, 123 insertions, 24 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index cc508dc..ec7b137 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -22126,18 +22126,33 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
const struct svc_gr_page *pp = &svc_fwd_req.gr_pages[i];
u64 hpa = 0;
const u8 *page;
+ u8 pbuf[SEMA_PAGE_SIZE];
u32 k;
if (pp->qmd_word != 32u || !pp->pa)
continue;
- kind = (pp->ap == SVC_APERTURE_FB) ? SVC_APERTURE_FB :
- SVC_APERTURE_SYS;
- if (svc_fwd_operand_hpa(vgpu, kind, pp->pa, 0,
- SEMA_PAGE_SIZE, &hpa, &off) || off)
- continue;
- page = (const u8 *)__va(hpa);
- if (!page)
- continue;
+ /*
+ * SESSION 140: read the page through the pin-aware reader
+ * first. The r791 evidence: the QMD page (va 0x4b85000)
+ * resolves to a vidmem shadow that reads empty, while the
+ * content the capture decoded comes from the push-buffer
+ * discovery's pinned staging copy - so a raw host mapping of
+ * pp->pa sees zeros and the pointer values never become
+ * candidates. svc_read_va consults ipin/pin/lat before the
+ * walk and returns the staged bytes.
+ */
+ if (!svc_read_va(vgpu, pp->va, pbuf, sizeof(pbuf))) {
+ page = pbuf;
+ } else {
+ kind = (pp->ap == SVC_APERTURE_FB) ? SVC_APERTURE_FB :
+ SVC_APERTURE_SYS;
+ if (svc_fwd_operand_hpa(vgpu, kind, pp->pa, 0,
+ SEMA_PAGE_SIZE, &hpa, &off) || off)
+ continue;
+ page = (const u8 *)__va(hpa);
+ if (!page)
+ continue;
+ }
for (k = 0x150u / 8u; k < 256; k++) {
u64 v = get_unaligned_le64(page + k * 8);
u64 wv;
@@ -22196,18 +22211,33 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
const struct svc_gr_page *pp = &svc_fwd_req.gr_pages[i];
u64 hpa = 0;
const u8 *page;
+ u8 pbuf[SEMA_PAGE_SIZE];
u32 k;
if (pp->qmd_word != 32u || !pp->pa)
continue;
- kind = (pp->ap == SVC_APERTURE_FB) ? SVC_APERTURE_FB :
- SVC_APERTURE_SYS;
- if (svc_fwd_operand_hpa(vgpu, kind, pp->pa, 0,
- SEMA_PAGE_SIZE, &hpa, &off) || off)
- continue;
- page = (const u8 *)__va(hpa);
- if (!page)
- continue;
+ /*
+ * SESSION 140: read the page through the pin-aware reader
+ * first. The r791 evidence: the QMD page (va 0x4b85000)
+ * resolves to a vidmem shadow that reads empty, while the
+ * content the capture decoded comes from the push-buffer
+ * discovery's pinned staging copy - so a raw host mapping of
+ * pp->pa sees zeros and the pointer values never become
+ * candidates. svc_read_va consults ipin/pin/lat before the
+ * walk and returns the staged bytes.
+ */
+ if (!svc_read_va(vgpu, pp->va, pbuf, sizeof(pbuf))) {
+ page = pbuf;
+ } else {
+ kind = (pp->ap == SVC_APERTURE_FB) ? SVC_APERTURE_FB :
+ SVC_APERTURE_SYS;
+ if (svc_fwd_operand_hpa(vgpu, kind, pp->pa, 0,
+ SEMA_PAGE_SIZE, &hpa, &off) || off)
+ continue;
+ page = (const u8 *)__va(hpa);
+ if (!page)
+ continue;
+ }
for (k = 0; k < SEMA_PAGE_SIZE / 8; k++) {
u64 v, wv;
@@ -22246,6 +22276,7 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
const struct svc_gr_page *pp = &svc_fwd_req.gr_pages[i];
u64 hpa = 0;
const u8 *page;
+ u8 pbuf[SEMA_PAGE_SIZE];
u32 k;
/* SESSION 139: include word 48 (see the r788 finding: the
@@ -22255,14 +22286,28 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
if (pp->qmd_word < 32 || pp->qmd_word > 48 ||
(pp->qmd_word & 1) || !pp->pa)
continue;
- kind = (pp->ap == SVC_APERTURE_FB) ? SVC_APERTURE_FB :
- SVC_APERTURE_SYS;
- if (svc_fwd_operand_hpa(vgpu, kind, pp->pa, 0,
- SEMA_PAGE_SIZE, &hpa, &off) || off)
- continue;
- page = (const u8 *)__va(hpa);
- if (!page)
- continue;
+ /*
+ * SESSION 140: read the page through the pin-aware reader
+ * first. The r791 evidence: the QMD page (va 0x4b85000)
+ * resolves to a vidmem shadow that reads empty, while the
+ * content the capture decoded comes from the push-buffer
+ * discovery's pinned staging copy - so a raw host mapping of
+ * pp->pa sees zeros and the pointer values never become
+ * candidates. svc_read_va consults ipin/pin/lat before the
+ * walk and returns the staged bytes.
+ */
+ if (!svc_read_va(vgpu, pp->va, pbuf, sizeof(pbuf))) {
+ page = pbuf;
+ } else {
+ kind = (pp->ap == SVC_APERTURE_FB) ? SVC_APERTURE_FB :
+ SVC_APERTURE_SYS;
+ if (svc_fwd_operand_hpa(vgpu, kind, pp->pa, 0,
+ SEMA_PAGE_SIZE, &hpa, &off) || off)
+ continue;
+ page = (const u8 *)__va(hpa);
+ if (!page)
+ continue;
+ }
/*
* relfix PART 3: whole page, matching the rewrite's scan
* range (it walks 0x0..0xfff qword-pairs); the old 0..0x7ff
@@ -22303,6 +22348,49 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
* inline-captured bytes as well (see svc_gr_scan_inline). */
svc_gr_scan_inline(wins, &n_cand, pp->va);
}
+ /*
+ * SESSION 140 (the n_data wiring): seed the candidate set with the
+ * launch's OWN QMD pointer pairs (words 34..47, already decoded into
+ * gr_qmd from the push's inline-QMD run). These ARE the launch's
+ * data-window pointers - the r792 evidence: the capture holds
+ * ptr[0]=0xdff0febc00 but the fill's page scans read only empty
+ * shadow pages (the QMD page's vidmem shadow is zero; its content
+ * never arrives - the invisible-vidmem-write class), so the pointer
+ * values could never become candidates and n_data stayed 0 (refused
+ * degenerate). The values need no page scan - use them directly.
+ */
+ {
+ u32 w2;
+
+ for (w2 = 0; w2 + 1 < 16; w2 += 2) {
+ u64 pv = (u32)svc_fwd_req.gr_qmd[34 + w2] |
+ ((u64)(svc_fwd_req.gr_qmd[35 + w2] &
+ 0x1ffffu) << 32);
+ u64 pw;
+ u32 fexp;
+
+ if (pv < 0x10000000ULL || pv >= (1ULL << 47) ||
+ (pv & 3))
+ continue;
+ fexp = (u32)(pv >> 23) & 0xffu;
+ if (fexp >= 0x6cu && fexp <= 0x8fu)
+ continue;
+ pw = pv & ~(u64)(SEMA_PAGE_SIZE - 1);
+ for (w = 0; w < n_cand; w++)
+ if (wins[w] == pw)
+ break;
+ if (w == n_cand && n_cand < ARRAY_SIZE(wins)) {
+ wins[n_cand++] = pw;
+ is_arg[n_cand - 1] = true;
+ if (svc_gr_pages_log < 64) {
+ svc_gr_pages_log++;
+ pr_info("sema-gr: qmd-ptr seed va=0x%llx (word %u) h=0x%x\n",
+ pw, 34 + w2,
+ svc_fwd_req.gr_h_object);
+ }
+ }
+ }
+ }
if (gsp_sema_dbg && svc_gr_pages_log < 48) {
svc_gr_pages_log++;
pr_info("sema-gr: fill cand n=%u pages=%u push=0x%llx\n",
@@ -23016,6 +23104,17 @@ static int svc_gr_req_fill(struct nv_vgpu_device *vgpu,
svc_gr_page_note(vgpu, svc_gr_cand.param_va, 32);
if (svc_gr_cand.prog_va)
svc_gr_page_note(vgpu, svc_gr_cand.prog_va, 48);
+ /*
+ * SESSION 140: the QMD page itself carries the launch's pointer
+ * VALUES (QMD words 32..49 live inside it - the param, the
+ * pointer-region pairs and the program). Without this note the fill
+ * never scans it, so the pointer values (r790: word 34 =
+ * 0xdff0febc00) can never become candidates and n_data stays 0
+ * (refused: degenerate data set). Noted under word 34 so the
+ * 32..48-even bank-page scan covers it.
+ */
+ if (svc_gr_cand.qmd_dev_va)
+ svc_gr_page_note(vgpu, svc_gr_cand.qmd_dev_va, 34);
for (i = 0; i < svc_gr_cand.n_pointer; i++)
svc_gr_page_note(vgpu, svc_gr_cand.pointer_va[i],
svc_gr_cand.pointer_word[i]);