summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c129
1 files changed, 111 insertions, 18 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 24ec36f..3887dbb 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -4454,6 +4454,16 @@ static struct svc_fwd_cand svc_fwd_cand;
#define SVC_GR_POINTER_MAX 8
#define SVC_GR_PAGES_MAX 16
/*
+ * relfix PART 3 (fill candidate superset): maximum distinct candidate pages
+ * per collection pass. Raised from 16 because the full-page scans added
+ * below (aligned with the rewrite's own whole-page scan) can legitimately
+ * carry more pointer-shaped words than the argument region alone; the old
+ * cap silently dropped the extra words, which then resurfaced as RELOC-GAP
+ * at rewrite time. It remains a hard bound with the historical silent-drop
+ * semantics beyond it (n_cand is logged in the fill summary).
+ */
+#define SVC_GR_CAND_MAX 24u
+/*
* m99: guest data identity-map capacity. The forwarded kernel's global data
* pages (discovered by scanning the param/const-0 page for device VAs) are
* resolved on the service thread and relocated into the engine-visible
@@ -14311,6 +14321,20 @@ static const char *svc_gr_src_probe(struct nv_vgpu_device *vgpu, u64 va,
}
/*
+ * relfix PART 3: append one attempt to the resolver's diagnostic chain
+ * ("name:rc,"). Bounded; the tail is simply dropped once full.
+ */
+static void svc_gr_reloc_stage_note(struct gsp_sema_gr_reloc *out,
+ const char *name, int rc)
+{
+ size_t n = strlen(out->stage);
+
+ if (n + 16 >= sizeof(out->stage))
+ return;
+ scnprintf(out->stage + n, sizeof(out->stage) - n, "%s:%d,", name, rc);
+}
+
+/*
* relfix (agent-A FIX A): rewrite-time GR relocation resolver (see
* gsp_sema_service.h). Mirrors the per-page source order of the fill
* (svc_gr_data_fill: svc_ipin_lookup -> svc_resolve_va's trusted chain ->
@@ -14328,6 +14352,9 @@ static const char *svc_gr_src_probe(struct nv_vgpu_device *vgpu, u64 va,
* for their publication snapshot and may sleep in vfio_dma_rw, exactly the
* discipline the walk comment above svc_walk_vaspaces mandates).
*
+ * Every attempt is recorded in out->stage ("name:rc," chain; the resolving
+ * source ends in ":0,") for the booter's RELOC-GAP-STAGE diagnostic.
+ *
* Returns 0 with out filled on a successful translation, -ENOENT on a miss
* (caller must leave the word untouched), or a conversion errno.
*/
@@ -14339,29 +14366,58 @@ int gsp_sema_gr_reloc_resolve(u64 va, struct gsp_sema_gr_reloc *out)
int ap = SVC_APERTURE_SYS;
u32 lap = 0, off = 0;
bool resolved = false;
- int ret;
+ int rc, ret;
if (!vgpu || !out)
return -EINVAL;
- if (!svc_ipin_lookup(page, &pa, &ap))
- resolved = true;
- else if (!svc_pin_lookup(page, &pa, &ap))
- resolved = true;
- else if (!svc_lat_lookup(page, &pa, &ap))
- resolved = true;
- else if (!svc_map_lookup(page, &pa))
- resolved = true;
- else if (!svc_walk_vaspaces(vgpu, page, &pa, &ap))
- resolved = true;
- else if (!svc_walk_discovered(vgpu, page, &pa, &ap))
+ out->stage[0] = '\0';
+ out->stage_rc = 0;
+
+ rc = svc_ipin_lookup(page, &pa, &ap);
+ svc_gr_reloc_stage_note(out, "ipin", rc);
+ if (!rc)
resolved = true;
+ if (!resolved) {
+ rc = svc_pin_lookup(page, &pa, &ap);
+ svc_gr_reloc_stage_note(out, "pin", rc);
+ if (!rc)
+ resolved = true;
+ }
+ if (!resolved) {
+ rc = svc_lat_lookup(page, &pa, &ap);
+ svc_gr_reloc_stage_note(out, "lat", rc);
+ if (!rc)
+ resolved = true;
+ }
+ if (!resolved) {
+ rc = svc_map_lookup(page, &pa);
+ svc_gr_reloc_stage_note(out, "map", rc);
+ if (!rc)
+ resolved = true;
+ }
+ if (!resolved) {
+ rc = svc_walk_vaspaces(vgpu, page, &pa, &ap);
+ svc_gr_reloc_stage_note(out, "vas", rc);
+ if (!rc)
+ resolved = true;
+ }
+ if (!resolved) {
+ rc = svc_walk_discovered(vgpu, page, &pa, &ap);
+ svc_gr_reloc_stage_note(out, "disc", rc);
+ if (!rc)
+ resolved = true;
+ }
if (!resolved) {
/* C1 fallback: a landing is a page the client already backed
* with content even when every resolver missed (r174). */
- if (svc_ledger_lookup(page, &lpa, &lap))
+ rc = svc_ledger_lookup(page, &lpa, &lap);
+ svc_gr_reloc_stage_note(out, "ledger", rc);
+ if (rc) {
+ out->stage_rc = -ENOENT;
return -ENOENT;
+ }
pa = lpa;
ap = (int)lap;
} else if (page >= SVC_VAS_FLOOR) {
@@ -14379,12 +14435,16 @@ int gsp_sema_gr_reloc_resolve(u64 va, struct gsp_sema_gr_reloc *out)
svc_ap_of(ap) == SVC_APERTURE_FB ?
SVC_APERTURE_FB : SVC_APERTURE_SYS,
pa, 0, SEMA_PAGE_SIZE, &hpa, &off);
- if (ret || off)
+ if (ret || off) {
+ svc_gr_reloc_stage_note(out, "hpa", ret ? ret : -EFAULT);
+ out->stage_rc = ret ? ret : -EFAULT;
return ret ? ret : -EFAULT;
+ }
out->pa = pa & ~(u64)(SEMA_PAGE_SIZE - 1);
out->ap = svc_ap_of(ap);
out->hpa = hpa;
+ out->stage_rc = 0;
return 0;
}
@@ -14420,7 +14480,7 @@ static void svc_gr_scan_cand(u64 *wins, u32 *n_cand, const u8 *data, u32 bytes)
for (w = 0; w < *n_cand; w++)
if (wins[w] == wv)
break;
- if (w == *n_cand && *n_cand < 16u)
+ if (w == *n_cand && *n_cand < SVC_GR_CAND_MAX)
wins[(*n_cand)++] = wv;
}
}
@@ -14470,8 +14530,8 @@ static bool svc_gr_hold_bound_expired(struct svc_channel *ch, u64 launch_va)
static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
struct svc_channel *ch)
{
- u64 wins[16];
- bool is_arg[16]; /* m150: candidate came from the argument scan */
+ u64 wins[SVC_GR_CAND_MAX];
+ bool is_arg[SVC_GR_CAND_MAX]; /* m150: candidate came from the arg scan */
u32 n_cand;
u32 off = 0, i, w;
u8 kind;
@@ -14575,6 +14635,34 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
if (w == n_cand && n_cand < ARRAY_SIZE(wins))
wins[n_cand++] = wv;
}
+ /*
+ * relfix PART 3 (fill candidate superset): the rewrite scans
+ * the WHOLE authored param page (0x0..0xfff) and re-resolves
+ * every device-VA-shaped word it finds; any word this scan
+ * does not collect resurfaces as a RELOC-GAP (r217: the two
+ * words the late path fixed were param/program descriptor
+ * fields below 0x150 / past 0x800 the argument scan never
+ * looked at). Collect the page remainder with the same shape
+ * test, after the argument region so the operand pages keep
+ * budget priority (m120/m121). Launch-internal pages remain
+ * filtered at resolution time below (R3 hygiene).
+ */
+ for (k = 0; k < SEMA_PAGE_SIZE / 8; k++) {
+ u64 v, wv;
+
+ if (k >= 0x150u / 8u && k < 256u)
+ continue; /* arg region: scanned above */
+ v = get_unaligned_le64(page + k * 8);
+ 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 < 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. */
@@ -14602,7 +14690,12 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
page = (const u8 *)__va(hpa);
if (!page)
continue;
- for (k = 0; k < 256; k++) {
+ /*
+ * relfix PART 3: whole page, matching the rewrite's scan
+ * range (it walks 0x0..0xfff qword-pairs); the old 0..0x7ff
+ * bound left the second half as permanent RELOC-GAPs.
+ */
+ for (k = 0; k < SEMA_PAGE_SIZE / 8; k++) {
u64 v = get_unaligned_le64(page + k * 8);
u64 wv;