summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_phys_booter.c111
-rw-r--r--kernel/gsp_sema_service.c82
2 files changed, 171 insertions, 22 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) {
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index bfed3b7..18d5e78 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -4449,19 +4449,25 @@ static bool svc_resolve_in_progress(u64 va)
*/
static u32 svc_cur_vas;
-static int svc_chanvas_lookup(struct nv_vgpu_device *vgpu, u64 va, u64 *addr,
- int *ap)
+/*
+ * r1483: walk the page tables of one specific published VAS handle. The
+ * render-target seed uses this with the VAS recorded by
+ * svc_surf_prelude_capture - a VA-keyed pin from another client's VAS must
+ * never answer for a surface the captured bind does not belong to.
+ */
+static int svc_vas_lookup_h(struct nv_vgpu_device *vgpu, u32 h_vaspace,
+ u64 va, u64 *addr, int *ap)
{
int i;
- if (!svc_cur_vas)
+ if (!h_vaspace)
return -ENOENT;
for (i = 0; i < SVC_MAX_VASPACES; i++) {
u64 pa = 0;
int a = SVC_APERTURE_SYS;
if (!svc.vas[i].valid ||
- svc.vas[i].h_vaspace != svc_cur_vas)
+ svc.vas[i].h_vaspace != h_vaspace)
continue;
if (svc_gmmu_walk(vgpu, svc.vas[i].pdb, svc.vas[i].entries,
va & ~(u64)(SEMA_PAGE_SIZE - 1),
@@ -4474,6 +4480,12 @@ static int svc_chanvas_lookup(struct nv_vgpu_device *vgpu, u64 va, u64 *addr,
return -ENOENT;
}
+static int svc_chanvas_lookup(struct nv_vgpu_device *vgpu, u64 va, u64 *addr,
+ int *ap)
+{
+ return svc_vas_lookup_h(vgpu, READ_ONCE(svc_cur_vas), va, addr, ap);
+}
+
/*
* SESSION 153-CONTINUED-67: which sub-source of svc_lookup_trusted answered
* the last call (1=channel VAS 2=pin 3=learned 4=discovered map 5=VAS walk
@@ -15894,9 +15906,28 @@ static u32 svc_surf_pre_flag = 1;
*/
static u64 svc_surf_pre_va;
static u32 svc_surf_pre_npages;
+/*
+ * SESSION 154 r1483: the VAS the captured colour-target bind came from.
+ * The pin/learned/map tables are keyed by VA ALONE, and every client's RM
+ * window sits at the same VAs (0x1200xxxxx): at r1482 the beef client held
+ * an injected pin for VA 0x120400000 (its own SYS allocation, guest PA
+ * 0x120400000) while the X server's screen surface of the SAME VA is a
+ * 900-page FB allocation. The fill seeded the captured surface VA and the
+ * global pin answered first, so the render-target recs became 10 pages of
+ * the beef client's buffer (the SASS-like content in the A-TRACE dump)
+ * instead of the screen the bind actually names. Resolve the captured
+ * surface through the page tables of the VAS that emitted the bind (the
+ * same channel-scoped rule as svc_chanvas_lookup, r835). Default 1;
+ * sema_gl_surf_vas=0 restores the legacy pin-first order for A/B.
+ */
+static u32 svc_surf_pre_hvas;
+static u32 svc_surf_vas_first = 1;
module_param_named(sema_surf_prelude_cap, svc_surf_pre_flag, uint, 0644);
MODULE_PARM_DESC(sema_surf_prelude_cap,
"Capture the last C597 colour-target bind (INC 0x800+j*0x40, fmt 0xe6) from trusted pushes so the GR launch builder can replay it ahead of 3D windows that carry no render target (default 1)");
+module_param_named(sema_gl_surf_vas, svc_surf_vas_first, uint, 0644);
+MODULE_PARM_DESC(sema_gl_surf_vas,
+ "Resolve the captured colour-target (render-target) pages through the page tables of the VAS that emitted the bind, before the global VA-keyed pin chain (default 1; 0 = legacy pin-first A/B)");
const u32 *gsp_sema_surf_prelude_get(u32 *n, u32 *gen)
{
@@ -15920,7 +15951,7 @@ bool gsp_sema_surf_va_get(u64 *va, u32 *npages)
return true;
}
-static void svc_surf_prelude_capture(const u8 *buf, u32 len)
+static void svc_surf_prelude_capture(const u8 *buf, u32 len, u32 h_vaspace)
{
u32 off = 0;
@@ -15971,12 +16002,16 @@ static void svc_surf_prelude_capture(const u8 *buf, u32 len)
svc_surf_pre_sig = sig;
svc_surf_pre_va = va;
WRITE_ONCE(svc_surf_pre_npages, (u32)npages);
+ /* r1483: remember which client VAS this bind belongs to (see
+ * svc_surf_pre_hvas): its page tables are the only authority
+ * for the surface's pages. */
+ WRITE_ONCE(svc_surf_pre_hvas, h_vaspace);
WRITE_ONCE(svc_surf_pre_gen, svc_surf_pre_gen + 1);
if (svc_surf_pre_log < 8) {
svc_surf_pre_log++;
- pr_info("sema-surf-pre: captured gen=%u words=%u va=0x%llx %ux%u fmt=0x%x hdr=%08x\n",
+ pr_info("sema-surf-pre: captured gen=%u words=%u va=0x%llx %ux%u fmt=0x%x hdr=%08x vas=0x%x\n",
svc_surf_pre_gen, n, va, v[2], v[3], v[4],
- hdr);
+ hdr, h_vaspace);
}
off += span * 4u;
}
@@ -16744,7 +16779,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
* channel. See svc_surf_prelude_capture.
*/
if (ch && trusted)
- svc_surf_prelude_capture(buf, len);
+ svc_surf_prelude_capture(buf, len, ch->h_vaspace);
memset(&st, 0, sizeof(st));
st.push_va = push_va;
@@ -32841,6 +32876,16 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
span = surf_cand_span;
surf_cand_used = true;
}
+ /*
+ * r1483: the captured surface's OWN VAS answers its pages
+ * first (see svc_surf_pre_hvas). The global pin/ledger layers
+ * are VA-keyed and another client's allocation sits at the
+ * same 0x1200xxxxx VA, which is how the render-target recs
+ * became 10 pages of the client's code/operand buffer.
+ */
+ u32 surf_vas_h = (surf_cand_va && base == surf_cand_va &&
+ READ_ONCE(svc_surf_vas_first)) ?
+ READ_ONCE(svc_surf_pre_hvas) : 0;
if (is_arg[w] && base >= 0x40000000000ULL)
n_arg_hi++;
@@ -32862,6 +32907,7 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
u32 ap = 0, x;
struct svc_gr_data *rec;
bool shadow_serve = false;
+ bool surf_vas_answered = false; /* r1483 */
int serve = SVC_GR_SHADOW_NONE;
bool real_content = false; /* r635 */
@@ -32884,8 +32930,24 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
{
u64 ipa = 0;
int iap = SVC_APERTURE_SYS;
+ u64 vpa = 0;
+ int vap = SVC_APERTURE_SYS;
- if (!svc_ipin_lookup(va, &ipa, &iap)) {
+ if (surf_vas_h &&
+ !svc_vas_lookup_h(vgpu, surf_vas_h, va,
+ &vpa, &vap)) {
+ static u32 surf_vas_log;
+
+ pa = vpa;
+ ap = (u32)vap;
+ cand_anchored = true;
+ surf_vas_answered = true;
+ if (surf_vas_log < 8u) {
+ surf_vas_log++;
+ pr_info("sema-gr: surf-vas h=0x%x va=0x%llx -> pa=0x%llx ap=%u (captured-surface VAS wins over the VA-keyed pin chain)\n",
+ surf_vas_h, va, pa, ap);
+ }
+ } else if (!svc_ipin_lookup(va, &ipa, &iap)) {
pa = ipa;
ap = (u32)iap;
cand_anchored = true;
@@ -33062,7 +33124,7 @@ static void svc_gr_data_fill(struct nv_vgpu_device *vgpu,
* aperture-aware (a SYS page and an FB page with the
* same numeric address are not the same page).
*/
- if (va >= SVC_VAS_FLOOR) {
+ if (va >= SVC_VAS_FLOOR && !surf_vas_answered) {
u64 lpa = 0;
u32 lap = 0;
u64 ipa = 0;