From ee2a38d7e6f308ae1ad4c59ef909f02309839539 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Mon, 5 Oct 2026 21:14:19 -0400 Subject: vgsp: track shadow ranges per record for multi-page GR buffers The inline-record path appends pages after the pointer pages, so the adjacent-entry heuristic missed the second param page. Record each shadowed range (base guest VA, line, mapped PTE count) and extend any page that continues a recorded range, up to 16 pages per 128 B line. --- kernel/gsp_phys_booter.c | 60 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index a008754..2200b4f 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -13124,9 +13124,13 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req, * multi-page buffer the QMD names once stays contiguous. */ { - u64 last_shadow_va = 0, last_guest_va = 0; - u32 last_shadow_line = 0; - bool last_shadow_valid = false; + struct { + u64 guest_va; /* base guest VA of the shadowed range */ + u64 shadow_va; /* line base VA (PTE0) */ + u32 line; /* scratch PT pool line index */ + u32 npte; /* mapped pages so far */ + } sh_rec[8]; + u32 n_sh_rec = 0; for (i = 0; i < req->n_pages; i++) { const struct gsp_phys_gr_page *pg = &req->pages[i]; @@ -13148,18 +13152,34 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req, else if (ret == -ENOSPC) gsp_phys_gr_pool_exhausted++; } - if (!mapped && pg->hpa && last_shadow_valid && - pg->qmd_word == GSP_PHYS_GR_QMD_WORD_NONE && - pg_va == last_guest_va + GSP_PHYS_PAGE_SIZE) { - u32 pte = (u32)((last_shadow_va >> 12) & 0xfu); - u64 va = 0; + /* + * A page with no QMD pointer of its own that continues a + * buffer already shadowed at an earlier array index (the + * inline records append pages after the pointer pages) gets + * the next PTE of that record's line, keeping base+offset + * access contiguous for the engine. + */ + if (!mapped && pg->hpa && + pg->qmd_word == GSP_PHYS_GR_QMD_WORD_NONE) { + u32 k; - if (pte + 1 < GSP_PHYS_RMCALL_GUEST_PT_CACHE_PTES && - !gsp_phys_rmcall_gr_map_shadow_contig_locked( - last_shadow_line, pte + 1, pg->hpa, &va)) { + for (k = 0; k < n_sh_rec; k++) { + u64 va = 0; + + if (pg_va != sh_rec[k].guest_va + + (u64)sh_rec[k].npte * + GSP_PHYS_PAGE_SIZE) + continue; + if (sh_rec[k].npte >= + GSP_PHYS_RMCALL_GUEST_PT_CACHE_PTES) + continue; + if (gsp_phys_rmcall_gr_map_shadow_contig_locked( + sh_rec[k].line, sh_rec[k].npte, + pg->hpa, &va)) + break; + sh_rec[k].npte++; mapped = true; - last_shadow_va = va; - last_guest_va = pg_va; + break; } } if (!mapped && pg->qmd_word != GSP_PHYS_GR_QMD_WORD_NONE && @@ -13240,10 +13260,16 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req, ~0x1ffffu) | ((u32)(ptr_va >> 32) & 0x1ffffu); mapped = true; - last_shadow_line = sh_line; - last_shadow_va = sh_va; - last_guest_va = pg_va; - last_shadow_valid = true; + if (n_sh_rec < ARRAY_SIZE(sh_rec)) { + sh_rec[n_sh_rec].guest_va = + pg_va; + sh_rec[n_sh_rec].shadow_va = + sh_va; + sh_rec[n_sh_rec].line = + sh_line; + sh_rec[n_sh_rec].npte = 1; + n_sh_rec++; + } } } } -- cgit v1.2.3