summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_phys_booter.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-05 12:22:00 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-05 12:22:00 -0500
commit17dcf049aca7b5a65d68389a110dc87d915a5393 (patch)
treeceb8c798af26b9d5e6d7d3d9655f0f475465fe98 /kernel/gsp_phys_booter.c
parenta3d801e394a1c57833c816edc3d3cee22dc4a78a (diff)
downloadopen-iov-17dcf049aca7b5a65d68389a110dc87d915a5393.tar.gz
open-iov-17dcf049aca7b5a65d68389a110dc87d915a5393.zip
vgsp-gr: re-target the captured render surface per launch so a partial VA-colliding allocation cannot receive the draw
The SURF-PRELUDE target pair was patched once per capture generation and then reused; the re-patch test was dead because gsp_sema_gr_surf_recs() only fills in the VA when it returns true and the code negated the call, so 'want' could never be computed. A later draw whose ~10-page SYS allocation sits at the same 0x1204xxxxx VA as the X server's 1280x720 screen inherited the X server's 900-page target; the engine's RT pair then named the client's command/operand buffer, which is why the 'surface' held method words and copy-out saw no engine pixels. Add gsp_phys_gr_surf_launch_target(): only a complete contiguous rec run for the captured surface may use its data-rec bounce lane; a partial run falls back to the boot-time contiguous alias built from the captured bind's VAS pages (the real screen HPAs). Re-patch whenever the cached pair differs from that effective target (SURF-PRELUDE retarget); RT0 copies the same words, so the RT0==RT1 design is unchanged. r1490 (VP_MODE=6 RT0=1, r1476-args): 15 launches, poison=0, retarget have=0xa000000 want=0x15e0000 for the partial lane then 900-page targets, output retirement up to 3/900 with 2 copy-out pages changed by engine, and a non-empty 3.69 MB xwd. New wall: the draw still produces no raster fragments - the only changed pages are the forced MME constant-buffer pages inside the screen (offset pages 768/772/773, 0xff000000 fills). Also harden tools/guest-diag/qga_fetch.py (retry open, long timeout, atomic .part write, clear error exit) for evidence capture.
Diffstat (limited to 'kernel/gsp_phys_booter.c')
-rw-r--r--kernel/gsp_phys_booter.c113
1 files changed, 87 insertions, 26 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index 6f2a858..d6ce2c2 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -25213,6 +25213,64 @@ static struct gsp_phys_gr_surf_keep gsp_phys_gr_surf[4];
static u32 gsp_phys_gr_surf_n;
/*
+ * r1490: the effective engine target of the captured surface ON THIS LAUNCH.
+ * The captured-surface rec set (gsp_sema_gr_surf_recs) is global - it is the
+ * last C597 colour-target bind a trusted channel emitted - while a launch's
+ * own data recs only cover it when the fill resolved the WHOLE span through
+ * the captured bind's VAS. Several clients share the same 0x1200xxxxx VAs:
+ * the beef client holds a ~10-page SYS allocation at 0x120400000, the X
+ * server's 1280x720 screen of the same VA is a 900-page FB allocation. A
+ * partial run must never win the rec-over-alias preference: the engine would
+ * be pointed at the client's code/operand buffer, its stores would land in
+ * (and its copy-in would read) method/SASS words instead of the screen, and
+ * the surface would look like it received the method stream.
+ *
+ * Complete rec run (contiguous base..last reloc VA) -> its bounce base, the
+ * path that lets the retire wait and copy-out see the pixels. Otherwise the
+ * per-boot contiguous alias built from the captured bind's VAS pages is the
+ * target: the engine writes the guest screen HPAs directly, exactly as the
+ * pre-r1483 alias path did. 0 = neither is available (caller keeps the
+ * per-page path).
+ */
+static u64 gsp_phys_gr_surf_launch_target(const struct gsp_phys_gr_submit *req)
+{
+ u64 sva = 0, last_va, base = 0, last = 0;
+ u32 sn = 0, di;
+ bool have_base = false, have_last = false;
+
+ if (!req)
+ return 0;
+ if (gsp_sema_gr_surf_recs(&sva, &sn) && sva && sn >= 2u) {
+ for (di = 0; di < req->n_data; di++) {
+ if (req->data[di].va == sva &&
+ req->data[di].reloc_va) {
+ base = req->data[di].reloc_va;
+ have_base = true;
+ break;
+ }
+ }
+ last_va = sva + ((u64)(sn - 1u) << 12);
+ for (di = 0; di < req->n_data; di++) {
+ if (req->data[di].va == last_va &&
+ req->data[di].reloc_va) {
+ last = req->data[di].reloc_va;
+ have_last = true;
+ break;
+ }
+ }
+ if (have_base && have_last &&
+ last == base + ((u64)(sn - 1u) << 12))
+ return base;
+ }
+ if (gsp_sema_surf_va_get(&sva, &sn)) {
+ for (di = 0; di < gsp_phys_gr_surf_n; di++)
+ if (gsp_phys_gr_surf[di].va == sva)
+ return gsp_phys_gr_surf[di].alias;
+ }
+ return 0;
+}
+
+/*
* SESSION 153-CONTINUED-27: slack tail for the alias. r994 measured the
* replay's colour writes landing past the declared w*h*4 footprint
* (1280x720x4 = 0x384000) by up to +0xE000 (11.2 rows) - FAULT_PTE on
@@ -29098,33 +29156,26 @@ gr_page_unmapped:
u64 want = 0;
/*
- * r1483: the rec-over-alias preference below
- * rewrites the pair to THIS launch's data-rec
- * bounce VA, and the fill alternates its
- * relocation half per capture push. A buffer
- * patched once per capture generation would
- * keep the first launch's half forever, so
- * re-patch when the launch's complete surface
- * rec names a different target.
+ * r1483/r1490: the rec-over-alias preference
+ * below rewrites the pair to THIS launch's
+ * data-rec bounce VA, and the fill alternates
+ * its relocation half per capture push. A
+ * buffer patched once per capture generation
+ * would keep the first launch's target
+ * forever - including the X server's 900-page
+ * rec lane when the next launch is the beef
+ * client whose partial 10-page allocation sits
+ * at the same VA. Re-patch whenever this
+ * launch's EFFECTIVE surface target (complete
+ * rec run or the contiguous alias, see
+ * gsp_phys_gr_surf_launch_target) differs
+ * from the cached words, so a partial launch
+ * always falls back to the real screen alias
+ * and never to its own code/operand buffer.
*/
if (!repatch && gsp_phys_gr_surf_pre_n >= 3) {
- u64 sva = 0;
- u32 sn = 0, di;
-
- if (!gsp_sema_gr_surf_recs(&sva, &sn) &&
- sva) {
- for (di = 0; di < req->n_data;
- di++) {
- if (req->data[di].va ==
- sva &&
- req->data[di]
- .reloc_va) {
- want = req->data[di]
- .reloc_va;
- break;
- }
- }
- }
+ want = gsp_phys_gr_surf_launch_target(
+ req);
if (want) {
u64 have =
((u64)(gsp_phys_gr_surf_pre[1] &
@@ -29132,8 +29183,18 @@ gr_page_unmapped:
(u64)(gsp_phys_gr_surf_pre[2] &
0xfffffffcu);
- if (have != want)
+ if (have != want) {
+ static u32 retarget_log;
+
repatch = true;
+ if (retarget_log < 16u) {
+ retarget_log++;
+ pr_info("vgsp-gr: SURF-PRELUDE retarget have=0x%llx want=0x%llx h=0x%x push=0x%llx\n",
+ have, want,
+ req->h_object,
+ req->push_va);
+ }
+ }
}
}
if (repatch) {