diff options
Diffstat (limited to 'kernel/gsp_phys_booter.c')
| -rw-r--r-- | kernel/gsp_phys_booter.c | 111 |
1 files changed, 99 insertions, 12 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c index 33e1b35..1cfa11f 100644 --- a/kernel/gsp_phys_booter.c +++ b/kernel/gsp_phys_booter.c @@ -27041,6 +27041,16 @@ int gsp_phys_backend_guest_gr_submit(const struct gsp_phys_gr_submit *req, gsp_phys_gr_wit_reset(); const u32 *win3d = NULL; u32 win3d_n = 0; + /* + * r1483: the SURF prelude emitted for THIS launch. The RT0 bind + * (sema_gl_rt0_bind) used to carry a constant 0xa000000 target; + * that is only correct when this launch's data-rec base is the 0xa + * half. The PS writes RT0 while the client binds RT1, so RT0 must + * name the same surface as the SURF prelude or half the launches + * store into the other half's (untracked) bounce window. When set, + * the RT0 run copies the emitted SURF run's target words. + */ + bool surf_pre_emitted = false; bool qmd_rel_redirected = false; /* r420b: release0 -> module sem */ u64 qmd_rel_hpa = 0, ch_rel_hpa = 0; u64 ch_sem_va = GSP_PHYS_RMCALL_VA_SEM + 4; @@ -28752,7 +28762,50 @@ gr_page_unmapped: sp = gsp_sema_surf_prelude_get(&spn, &spg); if (sp && spn && spg) { - if (spg != READ_ONCE(gsp_phys_gr_surf_pre_gen)) { + bool repatch = + spg != READ_ONCE(gsp_phys_gr_surf_pre_gen); + 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. + */ + 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; + } + } + } + if (want) { + u64 have = + ((u64)(gsp_phys_gr_surf_pre[1] & + 0xffu) << 32) | + (u64)(gsp_phys_gr_surf_pre[2] & + 0xfffffffcu); + + if (have != want) + repatch = true; + } + } + if (repatch) { u32 sdrop = 0, sn = spn; u32 srel; @@ -28771,12 +28824,21 @@ gr_page_unmapped: bar0, epoch); WRITE_ONCE(gsp_phys_gr_surf_pre_gen, spg); - pr_info("vgsp-gr: SURF-PRELUDE patched gen=%u raw=%u kept=%u dropped=%u reloc=%u h=0x%x push=0x%llx\n", - spg, sn, - gsp_phys_gr_surf_pre_n, - sdrop, srel, - req->h_object, - req->push_va); + { + static u32 surf_patch_log; + + if (surf_patch_log < 16u) { + surf_patch_log++; + pr_info("vgsp-gr: SURF-PRELUDE patched gen=%u raw=%u kept=%u dropped=%u reloc=%u target=0x%llx h=0x%x push=0x%llx\n", + spg, sn, + gsp_phys_gr_surf_pre_n, + sdrop, srel, + ((u64)(gsp_phys_gr_surf_pre[1] & 0xffu) << 32) | + (u64)(gsp_phys_gr_surf_pre[2] & 0xfffffffcu), + req->h_object, + req->push_va); + } + } } if (gsp_phys_gr_surf_pre_n && win3d_n + gsp_phys_gr_surf_pre_n + 2u + @@ -28792,6 +28854,7 @@ gr_page_unmapped: (size_t)gsp_phys_gr_surf_pre_n * 4u); win3d_n += gsp_phys_gr_surf_pre_n; + surf_pre_emitted = true; if (surf_emit_log < 16) { surf_emit_log++; pr_info("vgsp-gr: SURF-PRELUDE emitted words=%u window=%u h=0x%x push=0x%llx\n", @@ -28919,19 +28982,43 @@ gr_page_unmapped: 2u + 8u <= GSP_PHYS_RMCALL_GR_METHOD_WORDS) { u32 rt0_old = win3d_n; + u32 rt0_words[GSP_PHYS_GR_RT0_BIND_WORDS]; + memcpy(rt0_words, gsp_phys_gr_rt0_bind, + sizeof(rt0_words)); + /* + * r1483: RT0 and RT1 must name the SAME + * surface. The SURF prelude just emitted + * ahead of this run already carries the + * launch's real target after relocation + * (the data-rec bounce base when the + * surface rec set is complete, the + * contiguous alias otherwise); copy its + * geometry words so the PS's RT0 stores + * land in the tracked target on BOTH + * relocation halves. Without the SURF + * prelude (the window binds its own + * target) keep the historical constant. + */ + if (surf_pre_emitted && + gsp_phys_gr_surf_pre_n >= 7u) + memcpy(&rt0_words[1], + &gsp_phys_gr_surf_pre[1], + 6u * sizeof(u32)); memmove(&stream_patch[rt0_at + GSP_PHYS_GR_RT0_BIND_WORDS], &stream_patch[rt0_at], (size_t)(win3d_n - rt0_at) * 4u); - memcpy(&stream_patch[rt0_at], - gsp_phys_gr_rt0_bind, - sizeof(gsp_phys_gr_rt0_bind)); + memcpy(&stream_patch[rt0_at], rt0_words, + sizeof(rt0_words)); win3d_n += GSP_PHYS_GR_RT0_BIND_WORDS; if (rt0_emit_log < 16u) { rt0_emit_log++; - pr_info("vgsp-gr: RT0-BIND emitted window=%u->%u at=%u\n", - rt0_old, win3d_n, rt0_at); + pr_info("vgsp-gr: RT0-BIND emitted window=%u->%u at=%u target=0x%llx surf=%u\n", + rt0_old, win3d_n, rt0_at, + ((u64)(rt0_words[1] & 0xffu) << 32) | + (u64)(rt0_words[2] & 0xfffffffcu), + surf_pre_emitted ? 1u : 0u); } } else { if (rt0_skip_log < 8u) { |
