diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-05 21:01:17 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-10-05 21:01:17 -0400 |
| commit | 3c9d31151b8aa2d9e789de6787b1f18b84bb09d3 (patch) | |
| tree | bbe62306c8f18175e3a31009770729ceccd2b004 /kernel | |
| parent | fed5e574a3b326c384d5960dae9b7b7b5f94d9be (diff) | |
| download | open-iov-3c9d31151b8aa2d9e789de6787b1f18b84bb09d3.tar.gz open-iov-3c9d31151b8aa2d9e789de6787b1f18b84bb09d3.zip | |
vgsp: contiguous shadow PTEs for multi-page GR buffers (R4)
The mail launch's param buffer spans two pages but the QMD names only the
base page. The second page has no pointer word, so the Tier-2 shadow path
skipped it and the launch was refused. Map a page with no pointer word that
is contiguous with the previous shadow-mapped page into the next PTE of the
same 128 B fetch line (each line covers up to 16 consecutive 4 KB pages),
keeping the rewritten base-pointer buffer contiguous for the engine.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/gsp_phys_booter.c | 68 |
1 files changed, 67 insertions, 1 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index d90a683..a008754 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -12943,6 +12943,42 @@ static int gsp_phys_rmcall_gr_map_shadow_locked(u32 slot, u64 hpa, return 0; } +/* + * Tier-2 contiguity: write one more 4 KB page into an already-consumed + * shadow fetch line at PTE `pte` (0..CACHE_PTES-1) of that line, so a + * multi-page guest buffer whose base pointer was rewritten to the line base + * VA keeps its pages contiguous (the engine reads base+offset). Returns the + * page's VA. Called with gsp_phys_rm_lock held. + */ +static int gsp_phys_rmcall_gr_map_shadow_contig_locked(u32 line, u32 pte, + u64 hpa, u64 *va_out) +{ + struct gsp_phys_boot_chunk *pt; + u32 page, line_in_page; + u8 *pt_va; + + if (pte >= GSP_PHYS_RMCALL_GUEST_PT_CACHE_PTES) + return -EINVAL; + if (line >= GSP_PHYS_RMCALL_GUEST_PT_PAGES * + GSP_PHYS_RMCALL_GUEST_PT_LINES_PER_PAGE) + return -ENOSPC; + page = line / GSP_PHYS_RMCALL_GUEST_PT_LINES_PER_PAGE; + line_in_page = line % GSP_PHYS_RMCALL_GUEST_PT_LINES_PER_PAGE; + pt = &boot_stage.rmcall_chunks[GSP_PHYS_RMCALL_BUF_GUEST_PT0 + page]; + if (!pt->pages) + return -EIO; + pt_va = gsp_phys_chunk_page_va(pt, 0); + if (!pt_va) + return -EIO; + put_unaligned_le64(gsp_phys_rmcall_pte(hpa), + pt_va + (size_t)(GSP_PHYS_RMCALL_GUEST_PT_CACHE_PTES * + line_in_page + pte) * 8); + dma_wmb(); + *va_out = boot_stage.rmcall_va_guest_pt + ((u64)page << 21) + + ((u64)line_in_page << 16) + (u64)pte * GSP_PHYS_PAGE_SIZE; + return 0; +} + /* GR forward fault observation is armed by the GR parameters, not the CE * ones (gsp_phys_fault_relay_active() requires gsp_phys_work_forward). */ static bool gsp_phys_gr_fault_active(void) @@ -13082,8 +13118,16 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req, * Pages: Tier 1 maps the resolved HPA at the guest VA; a page without * a usable Tier-1 mapping falls to Tier 2 when captured inline bytes * cover it and a QMD pointer pair names it (the pair is rewritten to - * the shadow VA); anything else refuses the launch. + * the shadow VA); anything else refuses the launch. A page with no + * pointer pair of its own that is contiguous with the previous + * shadow-mapped page gets the next PTE of the same shadow line, so a + * 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; + for (i = 0; i < req->n_pages; i++) { const struct gsp_phys_gr_page *pg = &req->pages[i]; u64 pg_va, sh_va = 0; @@ -13104,6 +13148,20 @@ 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; + + 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)) { + mapped = true; + last_shadow_va = va; + last_guest_va = pg_va; + } + } 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 = @@ -13162,6 +13220,9 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req, copied++; } if (copied) { + u32 sh_line = + boot_stage.rmcall_guest_pt_next_line; + ret = gsp_phys_rmcall_gr_map_shadow_locked( n_shadow, (u64)gsp_phys_chunk_page_dma(sh, @@ -13179,6 +13240,10 @@ 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; } } } @@ -13193,6 +13258,7 @@ gr_page_unmapped: goto out; } } + } /* * Channel release: author it into the guest semaphore page when the |
