summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_phys_booter.c124
-rw-r--r--kernel/gsp_sema_service.c171
-rw-r--r--kernel/gsp_sema_service.h2
3 files changed, 286 insertions, 11 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index cf3107f..e43ba23 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -5280,7 +5280,7 @@ MODULE_PARM_DESC(sema_mme_post_ms,
*/
static u32 gsp_phys_mme_shadow_read(void __iomem *bar0, u32 nvclass, u32 mthd)
{
- iowrite32(nvclass | ((mthd & 0xfffu) << 16) | (1u << 30),
+ iowrite32(nvclass | (((mthd >> 2) & 0xfffu) << 16) | (1u << 30),
bar0 + 0x00404488u);
return ioread32(bar0 + 0x0040448cu);
}
@@ -19957,6 +19957,35 @@ module_param_named(sema_sph_bind_mask, gsp_phys_rmcall_gr_sph_bind_mask,
MODULE_PARM_DESC(sema_sph_bind_mask,
"Synth SPH-BIND slot mask (bit j = slot j; 0x20 = PS only, 0x01/0x10 = VSA/GS VTG image, 0x25 = VSA+PS) used when sema_gl_sph_bind=0");
+/*
+ * eng51 (CONT.512): the synthesized VSA/GS (j0/j4) bind the VTG SPH image.
+ * The historical address was family+0x900, but the live direct-GL family
+ * page reads zero there (c716: DS 0x86040624 with stage=01df0900,...).
+ * family+0x600 was tried as the VTG image (INLINE-WRITER: 0x020a0481), but
+ * the engine-visible alias shadow at +0x600 is the client's SASS upload
+ * (0x0b0b7208), so binding it poisons the DS (c718/c720: badf1201 with the
+ * j1 override off too). Default 0 = keep the historical +0x900 zero page
+ * until a real VTG SPH is authored at an engine-visible VA; A/B with 1.
+ */
+static bool gsp_phys_rmcall_gr_sph_vtg600;
+module_param_named(sema_gl_sph_vtg600, gsp_phys_rmcall_gr_sph_vtg600,
+ bool, 0644);
+MODULE_PARM_DESC(sema_gl_sph_vtg600,
+ "Bind the synthesized VSA/GS (j0/j4) stages to family+0x600 instead of the historical family+0x900 page (default 0: the live +0x600 alias shadow is SASS and poisons the DS)");
+
+/*
+ * eng51 A/B (c718): overriding the window's own slot-1 bind (j1) with the
+ * family+0x600 image is a separate question. c718 (override on) poisoned the
+ * DS (badf1201) while c716 (j0/j4 at 0x900, j1 at the client's 0x300 SASS
+ * pointer) reached 0x86040624, so the j1 override is default OFF until a
+ * same-boot A/B says otherwise.
+ */
+static bool gsp_phys_rmcall_gr_sph_vtg_j1;
+module_param_named(sema_gl_sph_vtg_j1, gsp_phys_rmcall_gr_sph_vtg_j1,
+ bool, 0644);
+MODULE_PARM_DESC(sema_gl_sph_vtg_j1,
+ "Also point the window's own slot-1 (VTG) bind at family+0x600 instead of the client's captured bind (default 0; c718 poison A/B)");
+
bool gsp_phys_rmcall_gr_sph_bind_value(void)
{
return READ_ONCE(gsp_phys_rmcall_gr_sph_bind);
@@ -30660,6 +30689,8 @@ gr_page_unmapped:
static u32 sph_bind_log;
u64 fam = req->prog_va &
~(u64)(GSP_PHYS_PAGE_SIZE - 1);
+ u64 vtg_va = READ_ONCE(gsp_phys_rmcall_gr_sph_vtg600) ?
+ (fam + 0x600u) : (fam + 0x900u);
u32 in[96], out[96];
u32 nfin = 0, nrun = 0, on = 0, odrop = 0, orel;
u32 bi;
@@ -30960,6 +30991,16 @@ gr_page_unmapped:
if (!va || nfin + 3u > 96u)
continue;
+ /*
+ * eng51: the window's own slot-1 bind can be
+ * a SASS pointer (c716: family+0x300 starts
+ * 0x0d0d7623); the VTG SPH image is at
+ * family+0x600. Point the VTG slot at the
+ * real image when the knob is on.
+ */
+ if (sl == 1u &&
+ READ_ONCE(gsp_phys_rmcall_gr_sph_vtg_j1))
+ va = vtg_va;
in[nfin++] = 0x20000000u | (2u << 16) |
((0x2014u + sl * 0x40u) >> 2);
in[nfin++] = (u32)(va >> 32) & 0xffu;
@@ -30981,9 +31022,7 @@ gr_page_unmapped:
(emit_j5 ? (bind_binding ? 8u : 7u) : 0u) +
(emit_gsimg ? (9u + ((gs_mode & 1u) ? 11u : 0u) +
((gs_ctx & 1u) ? 2u : 0u) +
- ((gs_ctx & 2u) ? 2u : 0u)) : 0u) +
- (emit_raster ? 17u : 0u) +
- (emit_raster_extra ? 16u : 0u)
+ ((gs_ctx & 2u) ? 2u : 0u)) : 0u)
<= 96u) {
/*
* SESSION 155 CONT 9: pair_safe emits each
@@ -31043,14 +31082,14 @@ gr_page_unmapped:
if (emit_j0) {
in[nfin++] = 0x20000000u | (2u << 16) |
(0x2014u >> 2);
- in[nfin++] = (u32)((fam + 0x900u) >> 32) & 0xffu;
- in[nfin++] = (u32)(fam + 0x900u) & 0xfffffffcu;
+ in[nfin++] = (u32)(vtg_va >> 32) & 0xffu;
+ in[nfin++] = (u32)vtg_va & 0xfffffffcu;
}
if (emit_j4) {
in[nfin++] = 0x20000000u | (2u << 16) |
(0x2114u >> 2);
- in[nfin++] = (u32)((fam + 0x900u) >> 32) & 0xffu;
- in[nfin++] = (u32)(fam + 0x900u) & 0xfffffffcu;
+ in[nfin++] = (u32)(vtg_va >> 32) & 0xffu;
+ in[nfin++] = (u32)vtg_va & 0xfffffffcu;
}
if (emit_j2) {
in[nfin++] = 0x20000000u | (2u << 16) |
@@ -31259,6 +31298,19 @@ gr_page_unmapped:
nrun++;
if (emit_gsimg)
nrun++;
+ } else if (sph_bind_log < 64u) {
+ /*
+ * eng51 (CONT.512): name the silent budget
+ * skip. Before this receipt the stage block
+ * (j0/j2/j4/j5/gsimg) could vanish while the
+ * prelude still emitted with only the j1 bind,
+ * leaving VSA/TCS/GS unbound and the DS latch
+ * at the a2040a04 class.
+ */
+ sph_bind_log++;
+ pr_info("vgsp-gr: SPH-BIND-STAGE-SKIP reason=budget nfin=%u mask=0x%x h=0x%x push=0x%llx\n",
+ nfin, sph_bind_mask, req->h_object,
+ req->push_va);
}
orel = gsp_phys_rmcall_gr_3d_patch_window(
in, nfin, out, &on, &odrop, req, &n_shadow,
@@ -31272,8 +31324,8 @@ gr_page_unmapped:
sph_bind_log++;
pr_info("vgsp-gr: SPH-BIND emitted fam=0x%llx win-binds=%u j0=0x%llx j2=0x%llx j4=0x%llx j5=0x%llx j1-type=0x11 rc=0x1a initblk=17 win=%u (pre=%u) h=0x%x push=0x%llx\n",
fam, req->n_prog_binds,
- fam + 0x900u, fam + 0x200u,
- fam + 0x900u, fam,
+ vtg_va, fam + 0x200u,
+ vtg_va, fam,
win3d_n, nfin,
req->h_object,
req->push_va);
@@ -37250,6 +37302,52 @@ static const struct file_operations gsp_phys_init_push_fops = {
};
/*
+ * eng51 (CONT.512): gsp-phys-last-push - the most recent >=4 KiB beef push
+ * (the direct-GL draw stream; c714: 0x4250110). Same text format as the
+ * init-push dump so the RT bind / draw methods can be decoded offline after
+ * the guest recycles its pushbuffer.
+ */
+static int gsp_phys_last_push_show(struct seq_file *m, void *unused)
+{
+ const u8 *buf;
+ u32 len, h, off;
+ u64 va;
+
+ buf = gsp_sema_last_cap_get(&len, &h, &va);
+ if (!len) {
+ seq_puts(m, "vgsp-last-push: empty (no later >=4 KiB beef push captured yet)\n");
+ return 0;
+ }
+ seq_printf(m, "vgsp-last-push: h=0x%x va=0x%llx len=%u\n", h, va, len);
+ for (off = 0; off + 4u <= len; off += 16u) {
+ u32 k, n = min_t(u32, 4u, (len - off) / 4u);
+
+ seq_printf(m, "%06x:", off);
+ for (k = 0; k < n; k++) {
+ u32 w;
+
+ memcpy(&w, buf + off + k * 4u, 4);
+ seq_printf(m, " %08x", w);
+ }
+ seq_putc(m, '\n');
+ }
+ return 0;
+}
+
+static int gsp_phys_last_push_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, gsp_phys_last_push_show, NULL);
+}
+
+static const struct file_operations gsp_phys_last_push_fops = {
+ .owner = THIS_MODULE,
+ .open = gsp_phys_last_push_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/*
* SESSION 153-CONTINUED-95: gsp-phys-ctx-dump - raw binary readback of the
* engine context buffer (see gsp_phys_ctx_readback_try). Empty until the
* first launch of the boot has run the CE readback.
@@ -37483,6 +37581,12 @@ int gsp_phys_boot_debugfs_init(void)
&gsp_phys_init_push_fops);
if (IS_ERR_OR_NULL(file))
pr_warn("vgsp-boot: debugfs file gsp-phys-init-push creation failed (init-push capture unavailable)\n");
+ /* eng51 (CONT.512): the most recent large beef push (direct-GL draw). */
+ file = debugfs_create_file("gsp-phys-last-push", 0444,
+ gsp_phys_debugfs_root, NULL,
+ &gsp_phys_last_push_fops);
+ if (IS_ERR_OR_NULL(file))
+ pr_warn("vgsp-boot: debugfs file gsp-phys-last-push creation failed (last-push capture unavailable)\n");
/*
* SESSION 153-CONTINUED-95: raw binary dump of the engine context
* buffer readback (64 KB from GSP_PHYS_RMCALL_VA_GR_CTX, taken once
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 9ba7ed0..96fabcf 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -11907,12 +11907,132 @@ static bool svc_gl_window_state_push(const u8 *buf, u32 len, u32 start_off)
return w0 == SVC_FB_STATE_LEAD;
}
+/*
+ * eng51 (CONT.512): the RT0-bearing class exemption for the beef draw
+ * window. The client's direct-GL draw window leads with a REAL
+ * colour-target bind run (INC cnt=6 at 0x840 binding the client's own
+ * surface class 0x0a000000/0x0c000000: A fmt<=1, B aligned <1<<30,
+ * W/H 0x780/0x438) and then continues with a large data region whose
+ * INC span (hdr 0x3100020x = INC cnt=0x100 mthd=0x804) makes the
+ * LAST-write heuristic (svc_gl_window_rt_valid) see values of the blob
+ * class at the RT methods (RT1 A=0xff B=0x000480a1 -> VA 0xff000480a0,
+ * W/H out of range), so the window was refused before SPH-BIND was ever
+ * reached (c704-6: `beef draw-synth: no valid last colour-target bind`,
+ * win=264 words @off=0x4b4). The engine walks the leading bind FIRST,
+ * so a window whose FIRST write to any target is a usable bind in the
+ * surface class is a legitimate rt0-bearing replay; windows whose only
+ * bind is the blob class (eng25 c344 garbage) stay refused.
+ */
+static bool svc_gl_rt0_class_admit = true;
+module_param_named(sema_gl_win_rt0_admit, svc_gl_rt0_class_admit, bool, 0644);
+MODULE_PARM_DESC(sema_gl_win_rt0_admit,
+ "Admit a beef draw-synth window to the verbatim replay lane when its FIRST colour-target write is a usable surface-class bind even if the last-write heuristic refuses it (default 1)");
+
+static bool svc_gl_window_rt_first_valid(const u8 *buf, u32 len, u32 start_off,
+ u32 at_off)
+{
+ u32 A[4] = { 0 }, B[4] = { 0 }, W[4] = { 0 }, H[4] = { 0 };
+ bool sa[4] = { false }, sb[4] = { false };
+ bool sw[4] = { false }, sh[4] = { false };
+ u32 o = start_off, j;
+
+ if (!buf || start_off >= at_off || at_off > len)
+ return false;
+ while (o + 4u <= at_off) {
+ u32 h, op, cnt, m, span = 1u, k;
+
+ memcpy(&h, buf + o, 4);
+ op = (h >> 29) & 7u;
+ cnt = (h >> 16) & 0xfffu;
+ m = (h & 0x1fffu) << 2;
+ if ((op == 1u || op == 3u || op == 5u) && cnt &&
+ o + 4u + cnt * 4u <= at_off)
+ span = 1u + cnt;
+ for (k = 0; k < span; k++) {
+ u32 mm = m + 4u * k, v = 0;
+
+ if (k && op != 1u && op != 3u)
+ break;
+ if (k)
+ memcpy(&v, buf + o + 4u + k * 4u, 4);
+ else if (op == 4u)
+ v = (h >> 16) & 0x1fffu;
+ else
+ continue;
+ for (j = 0; j < 4u; j++) {
+ u32 base = 0x800u + j * 0x40u;
+
+ if (mm == base && !sa[j]) {
+ A[j] = v; sa[j] = true;
+ } else if (mm == base + 4u && !sb[j]) {
+ B[j] = v; sb[j] = true;
+ } else if (mm == base + 8u && !sw[j]) {
+ W[j] = v; sw[j] = true;
+ } else if (mm == base + 0xcu && !sh[j]) {
+ H[j] = v; sh[j] = true;
+ }
+ }
+ }
+ o += span * 4u;
+ }
+ for (j = 0; j < 4u; j++)
+ if (sb[j] && sw[j] && sh[j] &&
+ (A[j] & ~0xffu) == 0 && (A[j] & 0xffu) <= 1u &&
+ B[j] >= 0x08000000u && B[j] < 0x40000000u &&
+ (B[j] & 3u) == 0 && W[j] > 0 && W[j] <= 0x4000u &&
+ H[j] > 0 && H[j] <= 0x4000u)
+ return true;
+ /*
+ * eng51: bounded miss witness. The c710-7 refusals were a 375-word
+ * window class (@off=0x640, push 0x40ef9d8/0x410f9d8) whose
+ * first-valid groups did not match the exemption; name the bytes
+ * and the groups so the next miss is one grep away.
+ */
+ {
+ static u32 rt0_miss_log;
+ u32 w0 = 0, w1 = 0, w2 = 0, w3 = 0;
+
+ if (gsp_sema_dbg && rt0_miss_log < 8u) {
+ rt0_miss_log++;
+ if (start_off + 16u <= at_off) {
+ memcpy(&w0, buf + start_off, 4);
+ memcpy(&w1, buf + start_off + 4, 4);
+ memcpy(&w2, buf + start_off + 8, 4);
+ memcpy(&w3, buf + start_off + 12, 4);
+ }
+ pr_info("sema-gl: RT0-FIRST-MISS start=0x%x at=0x%x w0..3=%08x %08x %08x %08x groups A=%08x,%08x,%08x,%08x B=%08x,%08x,%08x,%08x W=%08x,%08x,%08x,%08x H=%08x,%08x,%08x,%08x seen=%d%d%d%d/%d%d%d%d\n",
+ start_off, at_off, w0, w1, w2, w3,
+ A[0], A[1], A[2], A[3],
+ B[0], B[1], B[2], B[3],
+ W[0], W[1], W[2], W[3],
+ H[0], H[1], H[2], H[3],
+ sa[0], sa[1], sa[2], sa[3],
+ sb[0], sb[1], sb[2], sb[3]);
+ }
+ }
+ return false;
+}
+
static bool svc_gl_window_drawwin_ok(const u8 *buf, u32 len, u32 start_off,
u32 at_off)
{
if (svc_gl_window_state_push(buf, len, start_off))
return true;
- return svc_gl_window_rt_valid(buf, len, start_off, at_off);
+ if (svc_gl_window_rt_valid(buf, len, start_off, at_off))
+ return true;
+ if (READ_ONCE(svc_gl_rt0_class_admit) &&
+ svc_gl_window_rt_first_valid(buf, len, start_off, at_off)) {
+ static u32 rt0_adm_log;
+
+ if (rt0_adm_log < 16u) {
+ rt0_adm_log++;
+ pr_info("sema-gl: 3D mark admitted (RT0-bearing class: first-bind valid, last-write refused) start=0x%x at=0x%x win=%u words\n",
+ start_off, at_off,
+ at_off > start_off ? (at_off - start_off) / 4u : 0u);
+ }
+ return true;
+ }
+ return false;
}
static void svc_gl_flush(struct nv_vgpu_device *vgpu,
@@ -19892,6 +20012,18 @@ static u64 svc_init_cap_va;
static bool svc_init_cap_done;
static u32 svc_lmem_hits;
static u32 svc_lmem_seen;
+/*
+ * eng51 (CONT.512): the LAST large beef push of the boot. The init push is
+ * the channel-init/setup stream; the direct-GL draw arrives in a later push
+ * (c714: 0x4250110, 6400 B) that is transient in guest RAM. Preserve it so
+ * the RT bind / draw methods can be decoded offline after the guest has
+ * recycled the pushbuffer (gsp-phys-last-push).
+ */
+static u8 svc_last_cap[SVC_INIT_CAP_BYTES];
+static u32 svc_last_cap_len;
+static u32 svc_last_cap_h;
+static u64 svc_last_cap_va;
+static bool svc_last_cap_done;
static void svc_mme_prelude_capture(const u8 *buf, u32 len, u64 push_va,
u32 h_object);
@@ -19966,6 +20098,24 @@ static void svc_init_push_scan(const u8 *buf, u32 len, u64 push_va, u32 h_object
h_object, mn, mg, an, ag);
}
}
+ /*
+ * eng51 (CONT.512): keep the most recent large beef push too. The
+ * init capture above is one-shot (the channel-init stream); the
+ * direct-GL draw push arrives later and is the window the RT/draw
+ * admission must decode. Copy is bounded (64 KiB) and only for
+ * beef-family pushes that carry a non-zero head. 256 B (not 4 KiB):
+ * c716's direct-GL draw pushes are 2252/324 B, so the 4 KiB floor
+ * preserved only the 59 KB setup push.
+ */
+ if ((h_object & 0xfffff000u) == 0xbeef0000u &&
+ len >= 256u && len <= SVC_INIT_CAP_BYTES &&
+ memchr_inv(buf, 0, min_t(u32, len, 64u))) {
+ svc_last_cap_len = len;
+ memcpy(svc_last_cap, buf, len);
+ svc_last_cap_h = h_object;
+ svc_last_cap_va = push_va;
+ svc_last_cap_done = true;
+ }
}
const u8 *gsp_sema_init_cap_get(u32 *len, u32 *h, u64 *va, u32 *lmem_seen)
@@ -19977,6 +20127,14 @@ const u8 *gsp_sema_init_cap_get(u32 *len, u32 *h, u64 *va, u32 *lmem_seen)
return svc_init_cap;
}
+const u8 *gsp_sema_last_cap_get(u32 *len, u32 *h, u64 *va)
+{
+ *len = svc_last_cap_len;
+ *h = svc_last_cap_h;
+ *va = svc_last_cap_va;
+ return svc_last_cap;
+}
+
/*
* SESSION 153-CONTINUED-53: MME context-setup prelude buffer.
*
@@ -31123,6 +31281,17 @@ static bool svc_gr_ram_ring_scan(struct nv_vgpu_device *vgpu,
u64 chunk = min_t(u64, SVC_SCAN_CHUNK, end - gpa);
u32 o;
+ /*
+ * eng51 (CONT.512): the linear scan walks the guest's
+ * non-RAM windows too (legacy VGA/BIOS below 1 MiB and the
+ * sub-4-GiB PCI hole). Every 64 KiB read there fails, and
+ * the per-GPA witness used to emit ~32k lines per sweep,
+ * rotating dmesg and hiding the draw-capture evidence.
+ * Those windows can never hold the ring; skip them.
+ */
+ if ((gpa >= 0xa0000ULL && gpa < 0x100000ULL) ||
+ (gpa >= 0x80000000ULL && gpa < 0x100000000ULL))
+ continue;
if (svc_read(vgpu, gpa, buf, chunk)) {
if (gsp_sema_dbg &&
(ch->h_object & 0xfffff000u) == 0xbeef0000u) {
diff --git a/kernel/gsp_sema_service.h b/kernel/gsp_sema_service.h
index b40dad2..f2a0777 100644
--- a/kernel/gsp_sema_service.h
+++ b/kernel/gsp_sema_service.h
@@ -305,6 +305,8 @@ void gsp_sema_service_fwd_gr_stats(u64 *req, u64 *ok, u64 *fallback,
* emitted the download-state local-memory block).
*/
const u8 *gsp_sema_init_cap_get(u32 *len, u32 *h, u64 *va, u32 *lmem_seen);
+/* eng51 (CONT.512): the most recent >=4 KiB beef push (direct-GL draw). */
+const u8 *gsp_sema_last_cap_get(u32 *len, u32 *h, u64 *va);
/*
* Discover and pin GR (compute) channel rings after the CE region of the