diff options
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 129 |
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; |
