diff options
Diffstat (limited to 'kernel/gsp_phys_booter.c')
| -rw-r--r-- | kernel/gsp_phys_booter.c | 85 |
1 files changed, 71 insertions, 14 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index 60b6ea4..3c2da44 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -17113,8 +17113,21 @@ static u32 gsp_phys_gr_data_bi(u64 reloc_va) * bounce_csum_in. */ #define GSP_PHYS_GR_GAP_MAX 4096u /* total late pages per launch */ -#define GSP_PHYS_GR_GAP_SPAN_MAX 2048u /* contiguous pages per word */ +/* + * relfix PART 3 (r217 span containment): the late path authors ONLY the + * pages actually needed by the fixed word. r217 showed two fixed words + * (the launch's own param/program descriptor fields, which the fill skips + * as launch-internal) walking ~1242 fully-mapped neighbour pages each - + * 2484 late pages, ~10 MB copied in and out per launch, for zero engine + * writes - and the clients converted from fast-fail (~60 s verdict) to + * killed at 250 s. The span is now a small fetch line, not a region walk: + * the multi-page operand class is owned by the fill's own span pipeline + * (which the PART 3 candidate superset now feeds), and this path is a + * last-resort proxy for words the fill could not own. + */ +#define GSP_PHYS_GR_GAP_SPAN_MAX 16u /* contiguous pages per word max */ #define GSP_PHYS_GR_GAP_WORD_MAX 32u /* distinct fixed words per launch */ +#define GSP_PHYS_GR_GAP_LOG_MAX 16u /* distinct gap VAs stage-logged */ struct gsp_phys_gr_gap_page { u64 va; /* device VA of the page (unique-proxy key) */ u64 hpa; /* guest page copied in (results copied back to) */ @@ -17134,6 +17147,8 @@ static struct gsp_phys_gr_gap_word static u32 gsp_phys_gr_gap_word_n; static u64 gsp_phys_gr_reloc_fixed; /* words rewritten this launch */ static u64 gsp_phys_gr_reloc_fixed_first; /* first fixed device VA */ +static u64 gsp_phys_gr_gap_logged[GSP_PHYS_GR_GAP_LOG_MAX]; +static u32 gsp_phys_gr_gap_logged_n; /* * relfix: reloc VA of the i-th bounce-region index, region mode exactly as @@ -17207,18 +17222,49 @@ static bool gsp_phys_gr_page_tracked(const struct gsp_phys_gr_submit *req, } /* + * relfix PART 3: one rate-limited RELOC-GAP-STAGE line per distinct gap VA + * per launch. `stage` is the resolver source chain (r.stage, e.g. + * "ipin:-2,pin:-2,lat:-2,map:-2,vas:-2,disc:-2,ledger:-2," - the resolving + * source ends in ":0,") for a word no source answered, or a short authoring + * refusal token ("span-overlap", "region-full", "wordmax-full", + * "base-tracked") for a word that resolved but was deliberately not + * authored. Together with rc=-1/errno this classifies every remaining gap: + * chain-of-misses = unresolvable at rewrite time (compare the fill's view of + * the same VA); "span-overlap"/"region-full" = resolvable but refused for + * proxy-safety/capacity; "wordmax-full" = table bound hit. + */ +static void gsp_phys_gr_gap_stage_log(u64 va, const char *stage, int rc) +{ + u32 i; + + for (i = 0; i < gsp_phys_gr_gap_logged_n; i++) + if (gsp_phys_gr_gap_logged[i] == va) + return; + if (gsp_phys_gr_gap_logged_n < ARRAY_SIZE(gsp_phys_gr_gap_logged)) + gsp_phys_gr_gap_logged[gsp_phys_gr_gap_logged_n++] = va; + pr_info_ratelimited("vgsp-gr: RELOC-GAP-STAGE va=0x%llx stage=%s rc=%d\n", + va, stage, rc); +} + +/* * relfix: resolve and author one unmatched word (see gsp_phys_gr_gap_page). * The base VA resolves through the sema service's trusted resolver; on a hit * the page is queued and the word rewritten to <reloc VA> | offset - the - * exact encoding the matched-word relocation uses - and the contiguous span - * the resolver also answers (bounded) is queued behind it so a multi-page - * operand's base+offset reads stay contiguous, exactly like a fill-tracked - * span. A repeated word (same base VA authored in another QMD page) reuses - * its recorded reloc VA. NEVER guesses: only a successful resolve rewrites, - * and a page that already has a proxy (the fill's or an earlier fix's) stops - * the fix - the queued pages of THIS word are rolled back and the word stays - * a RELOC-GAP - so one guest page can never gain a second copy-out writer - * (the clobber class gsp_phys_gr_page_tracked describes). + * exact encoding the matched-word relocation uses - and up to + * GSP_PHYS_GR_GAP_SPAN_MAX contiguous pages the resolver also answers are + * queued behind it so a small operand's base+offset reads stay contiguous. + * PART 3 (r217): that span is a small fetch line (16 pages), NOT a region + * walk - r217's 1242-page spans turned fast fails into 250 s kills; the + * multi-page operand class belongs to the fill's own span pipeline, which + * the PART 3 candidate superset now feeds. A repeated word (same base VA + * authored in another QMD page) reuses its recorded reloc VA. NEVER guesses: + * only a successful resolve rewrites, and a page that already has a proxy + * (the fill's or an earlier fix's) stops the fix - the queued pages of THIS + * word are rolled back and the word stays a RELOC-GAP - so one guest page + * can never gain a second copy-out writer (the clobber class + * gsp_phys_gr_page_tracked describes). Every word that stays a gap is + * stage-logged once (RELOC-GAP-STAGE) with the resolver chain or the + * authoring refusal token. */ static bool gsp_phys_gr_reloc_fix_word(const struct gsp_phys_gr_submit *req, u32 *w, u32 k, u32 *mirror) @@ -17241,15 +17287,24 @@ static bool gsp_phys_gr_reloc_fix_word(const struct gsp_phys_gr_submit *req, bool overlap = false; u64 base_pa; - if (gsp_phys_gr_gap_word_n >= GSP_PHYS_GR_GAP_WORD_MAX) + if (gsp_phys_gr_gap_word_n >= GSP_PHYS_GR_GAP_WORD_MAX) { + gsp_phys_gr_gap_stage_log(wb, "wordmax-full", + -ENOSPC); return false; - if (gsp_phys_gr_page_tracked(req, wb)) + } + if (gsp_phys_gr_page_tracked(req, wb)) { + gsp_phys_gr_gap_stage_log(wb, "base-tracked", -EEXIST); return false; - if (gsp_sema_gr_reloc_resolve(wb, &r)) + } + if (gsp_sema_gr_reloc_resolve(wb, &r)) { + gsp_phys_gr_gap_stage_log(wb, r.stage, r.stage_rc); return false; + } base_pa = r.pa; - if (!gsp_phys_gr_gap_add(req->n_data, wb, r.hpa, &reloc_va)) + if (!gsp_phys_gr_gap_add(req->n_data, wb, r.hpa, &reloc_va)) { + gsp_phys_gr_gap_stage_log(wb, "region-full", -ENOSPC); return false; + } for (i = 1; i < GSP_PHYS_GR_GAP_SPAN_MAX; i++) { u64 va = wb + ((u64)i << 12); u64 ignored = 0; @@ -17279,6 +17334,7 @@ static bool gsp_phys_gr_reloc_fix_word(const struct gsp_phys_gr_submit *req, * the engine's next base+offset read land on a * later word's page. */ + gsp_phys_gr_gap_stage_log(wb, "span-overlap", -EEXIST); gsp_phys_gr_gap_n = gap_start; return false; } @@ -17765,6 +17821,7 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req, gsp_phys_gr_gap_word_n = 0; gsp_phys_gr_reloc_fixed = 0; gsp_phys_gr_reloc_fixed_first = 0; + gsp_phys_gr_gap_logged_n = 0; /* * The fault record is static scratch (frame bound): reset it per * submission so a previous launch's fault can never leak into this |
