summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-05 21:34:36 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-05 21:34:36 -0400
commite0e96fe151e9bf690dd215e46da135da1dcc2317 (patch)
tree797f88b8e38d9aac5964356c5c583aae02c08362 /kernel/gsp_phys_booter.c
parentee2a38d7e6f308ae1ad4c59ef909f02309839539 (diff)
downloadopen-iov-e0e96fe151e9bf690dd215e46da135da1dcc2317.tar.gz
open-iov-e0e96fe151e9bf690dd215e46da135da1dcc2317.zip
vgsp: alias-map indirect high-VA GR pages and fix up shadow pointers
The mail kernel's output buffer has no QMD pointer word; the engine reaches it through a pointer inside the parameter bank, so the Tier-1 refusal at its high VA killed the launch. Alias-map such a page's guest HPA at a fresh ladder line and rewrite every matching 8-byte pointer inside the shadowed copy pages (param/program) to the alias, so engine writes land in the guest's own page and the guest's DtoH sees them.
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c64
1 files changed, 64 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 2200b4f..b95bd81 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -13128,7 +13128,9 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
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 slot; /* member host page in the shadow chunk */
u32 npte; /* mapped pages so far */
+ bool copy; /* true = copy, false = guest HPA alias */
} sh_rec[8];
u32 n_sh_rec = 0;
@@ -13144,6 +13146,8 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
goto out;
}
pg_va = pg->guest_va & ~(u64)(GSP_PHYS_PAGE_SIZE - 1);
+ pr_info("vgsp-gr: page[%u] va=0x%llx hpa=0x%llx qmd_word=%u\n",
+ i, pg->guest_va, pg->hpa, pg->qmd_word);
if (pg->hpa) {
ret = gsp_phys_rmcall_gr_map_va_locked(bar0, pg_va,
pg->hpa, epoch);
@@ -13182,6 +13186,66 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req,
break;
}
}
+ /*
+ * Indirect high-VA write/read target (no QMD pointer of its
+ * own; e.g. the kernel's output buffer, referenced from the
+ * parameter bank): alias-map the guest page's HPA at a fresh
+ * ladder line and rewrite matching pointers inside the
+ * already-shadowed copy pages (param/program) to the alias,
+ * so engine accesses land in the guest's own page.
+ */
+ if (!mapped && pg->hpa &&
+ pg->qmd_word == GSP_PHYS_GR_QMD_WORD_NONE) {
+ u32 sh_line = boot_stage.rmcall_guest_pt_next_line;
+
+ if (n_shadow < GSP_PHYS_RMCALL_GR_SHADOW_PAGES &&
+ !gsp_phys_rmcall_gr_map_shadow_locked(
+ n_shadow, pg->hpa, &sh_va)) {
+ u32 k, slot = n_shadow;
+
+ mapped = true;
+ n_shadow++;
+ 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].slot = slot;
+ sh_rec[n_sh_rec].npte = 1;
+ sh_rec[n_sh_rec].copy = false;
+ n_sh_rec++;
+ }
+ for (k = 0; k < n_sh_rec; k++) {
+ u8 *cp;
+ u32 off;
+
+ if (!sh_rec[k].copy)
+ continue;
+ cp = gsp_phys_chunk_page_va(
+ &boot_stage.rmcall_gr_shadow,
+ sh_rec[k].slot);
+ if (!cp)
+ continue;
+ for (off = 0; off + 8 <=
+ GSP_PHYS_PAGE_SIZE;
+ off += 8) {
+ u64 v = get_unaligned_le64(
+ cp + off);
+
+ if ((v & ~(u64)(GSP_PHYS_PAGE_SIZE
+ - 1)) != pg_va)
+ continue;
+ put_unaligned_le64(
+ sh_va + (v &
+ (u64)(GSP_PHYS_PAGE_SIZE
+ - 1)),
+ cp + off);
+ }
+ }
+ dma_wmb();
+ pr_info("vgsp-gr: indirect page va=0x%llx aliased at 0x%llx (shadow slot %u); copy pointers fixed up\n",
+ pg->guest_va, sh_va, slot);
+ }
+ }
if (!mapped && pg->qmd_word != GSP_PHYS_GR_QMD_WORD_NONE &&
pg->qmd_word + 1 < GSP_PHYS_GR_QMD_WORDS) {
struct gsp_phys_boot_chunk *sh =