summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c85
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