summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-28 04:42:56 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-28 04:42:56 -0400
commit23fc40666a29ec748890d64f2bed5b9ad26ee634 (patch)
tree3b6a16ffdcea9f6d2c264a5b692ac736d0d3a37a /kernel/gsp_sema_service.c
parent916db0d5a81974c5799242c0df601ae5bbb5ebd6 (diff)
downloadopen-iov-23fc40666a29ec748890d64f2bed5b9ad26ee634.tar.gz
open-iov-23fc40666a29ec748890d64f2bed5b9ad26ee634.zip
vgsp: GL section capture + synthesized launch reaches the engine (SESSION 149 r888)
- M1.1a: preserve the bracketing release across the section-open reset; allow hash-verified replay capture (exactly-once guard). First trusted pass now captures the GL setup section (push=0x120010004, prog=0x121201b00, rel=0x120001000, replay=0). - M1.1b: per-channel ring scan 16->24 slices + put-triggered keep-alive. - M2-S1: booter skips w48 Tier-1 when shadow_win0 is set; flush attaches the observed LID payload as an inline record. - Evidence (r888): 'qmd_word 48 page copied to window-0 shadow'; 'GR LAUNCH submitted pages=5 shadow=1 qmdwin=0x108000'; FAULT-CAP code_src=win0, code64 non-zero, FAULT_PDE count=0 (engine fetched the shadowed code). - Remaining wall: SKEDCHECK06_REGISTER_COUNT + SKEDCHECK16_CTA_THREAD_DIM_ZERO (synthesized QMD scheduling fields) -> bounded fail + SW release. Feature gated by sema_gl_xlate (default off).
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c417
1 files changed, 413 insertions, 4 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index cc9282e..3cc9936 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -187,7 +187,14 @@ struct sema_map_entry {
* slice per service pass so the service thread stays responsive.
*/
#define SVC_GR_RAM_SLICE (512ULL << 20) /* guest RAM per pass */
-#define SVC_GR_RAM_PASS_MAX 16 /* slices before giving up */
+/*
+ * SESSION 149 R15 (M1.1b): 24 slices cover two full sweeps of the 6 GB
+ * guest before the boot-time budget retires; the put-triggered keep-alive
+ * in the pump grants up to SVC_GR_RAM_REFRESH_MAX further budgets.
+ */
+#define SVC_GR_RAM_PASS_MAX 24 /* slices before a budget retires */
+#define SVC_GR_RAM_REFRESH_MAX 3 /* keep-alive budget refreshes */
+#define SVC_GR_RAM_REFRESH_MS 10000 /* minimum spacing between them */
#define SVC_GR_RAM_WIN (2ULL << 20) /* allocation window pinned */
struct svc_channel {
@@ -499,6 +506,17 @@ struct svc_channel {
u8 gr_ram_passes; /* slices walked so far */
bool gr_ram_logged; /* one discovery line per channel */
/*
+ * SESSION 149 R15 (M1.1b keep-alive): the boot-time slice budget can
+ * exhaust long before the client creates its ring objects (r886: 16
+ * slices spent, the GL client's ring never scanned, no pairing). A
+ * GPFIFO put advance proves the client is live, so grant a fresh
+ * bounded budget - spaced and capped so a never-found ring cannot
+ * keep the scan hot.
+ */
+ u32 gr_ram_kick; /* put value at the last budget refresh */
+ u8 gr_ram_refreshes; /* budget refreshes granted so far */
+ unsigned long gr_ram_refresh_at; /* next eligible refresh */
+ /*
* r496e: true when the ring was found by the RAM content scan (a
* kernel-RM sysmem channel - the X/GL 3D channel). Such a channel's
* pushes are 2D/3D method streams the emulation does not execute;
@@ -6617,6 +6635,8 @@ static_assert(sizeof(struct svc_gr_page) == 24,
"the sema GR page descriptor must stay {u64,u64,u8,u32} = 24 bytes");
static u64 svc_push_hash(const u8 *p, u32 len);
+/* SESSION 149 R15: exactly-once guard for the hash-verified replay capture. */
+static bool svc_gr_cand_push_seen(u64 push_va, u64 hash);
/* QMD field decode: the exact shape the host CUDA bridge uses. */
static void svc_gr_qmd_decode(struct svc_gr_cand_rec *c)
@@ -6756,6 +6776,247 @@ static void svc_gr_cand_capture(struct svc_channel *ch,
}
/*
+ * SESSION 149 R14 (sema_gl_xlate, default 0 = off): GL/3D direct method
+ * stream -> synthesized GR candidate recognizer.
+ *
+ * The GL channel's large per-frame pushes bind the TURING_A 3D class
+ * (0xC597) on the channel subchannel and carry no CUDA QMD, so the
+ * inline-QMD capture above never fires for them (the victim-section
+ * classification of the r882 stream, push VA 0x120010004 / 1524 B:
+ * SET_OBJECT C597, SET_TEX_HEADER_POOL_A -> 0x1214fa220/0x10, 20x
+ * LINE_LENGTH_IN(0x180)+LAUNCH_DMA(0x1b0) inline uploads to
+ * 0x1214f8f00+0x100k, SET_PIPELINE_PROGRAM_ADDRESS_A/B(0x2014/0x2018
+ * + j*64) -> 0x121201b00, BIND_GROUP_CONSTANT_BUFFER(0)). This section
+ * collects the OBSERVED VA operands (nothing is invented) and synthesizes
+ * the 64-word QMD those fields would carry; the candidate then flows
+ * through the unchanged svc_gr_request / svc_fwd_gr_work /
+ * gsp_phys_backend_guest_gr_submit machinery.
+ *
+ * Strictly additive: gated by sema_gl_xlate and inert for every stream
+ * without the C597 class bind (0xC5B5 copy-class and 902D 2D binds never
+ * open a section). Class numbers from the public class headers
+ * (clc597.h: TURING_A 0xC597).
+ */
+static bool gsp_sema_gl_xlate;
+module_param_named(sema_gl_xlate, gsp_sema_gl_xlate, bool, 0644);
+MODULE_PARM_DESC(sema_gl_xlate,
+ "GL/3D (C597) direct stream -> synthesized GR candidate (default 0 = off)");
+
+struct svc_gl_sec {
+ bool seen;
+ u32 subch;
+ u64 prog_va; /* SET_PIPELINE_PROGRAM_ADDRESS_A/B(j) upper|lower */
+ u64 param_va; /* SET_TEX_HEADER_POOL_A/B/C upper|lower */
+ u32 param_size; /* observed pool value word (0x10 on the r882 stream) */
+ u64 rel_va; /* last VALID release decoded on the channel */
+ u32 rel_payload;
+ u64 ptr[SVC_GR_POINTER_MAX];
+ u32 n_ptr;
+ /*
+ * SESSION 149 R15 (M2-S1): bytes of the first LAUNCH_DMA /
+ * LOAD_INLINE_DATA run observed inside the section (the observed
+ * upload payload). Attached to the synthesized candidate as an
+ * inline record at the program VA so the backend's window-0 shadow
+ * copy has a non-empty source even when the guest program page
+ * resolves empty (the GL program page is not among the section's
+ * own upload destinations).
+ */
+ u8 blob[SVC_GR_INLINE_BYTES];
+ u32 blob_len;
+};
+static struct svc_gl_sec svc_gl; /* service thread only */
+static u32 svc_gl_rep_log; /* bounded replay-already-captured witness */
+
+static void svc_gl_add_ptr(u64 va)
+{
+ u32 k;
+
+ if (!va)
+ return;
+ for (k = 0; k < svc_gl.n_ptr; k++)
+ if (svc_gl.ptr[k] == va)
+ return;
+ if (svc_gl.n_ptr < SVC_GR_POINTER_MAX - 1)
+ svc_gl.ptr[svc_gl.n_ptr++] = va;
+}
+
+/*
+ * Collect one observed VA operand from the open C597 section. Every case
+ * is transcribed from the decoded r882 stream words; the upper-word masks
+ * follow the class definitions (ADDRESS_UPPER 7:0 / lower 31:0).
+ */
+static void svc_gl_field(u32 addr, u32 count, const u8 *data, u32 dlen)
+{
+ u32 v[4] = { 0, 0, 0, 0 };
+ u32 n = count > 4 ? 4 : count, k;
+
+ for (k = 0; k < n; k++) {
+ if (4 * (k + 1) > dlen)
+ break;
+ memcpy(&v[k], data + 4 * k, 4);
+ }
+ /* SET_PIPELINE_PROGRAM_ADDRESS_A/B(j), A=upper(7:0), B=lower(31:0).
+ * Observed: 0x20020815 (j=1) [00000001 21201b00] -> 0x121201b00.
+ */
+ if (addr >= 0x2014 && addr < 0x4000 && (addr & 0x3f) == 0x14 &&
+ count >= 2 && !svc_gl.prog_va) {
+ svc_gl.prog_va = ((u64)(v[0] & 0xff) << 32) |
+ (u64)(v[1] & 0xfffffffc);
+ return;
+ }
+ switch (addr) {
+ case 0x1574: /* SET_TEX_HEADER_POOL_A/B/C: upper, lower, index.
+ * Observed: [00000001 214fa220 00000010].
+ */
+ if (count >= 3 && !svc_gl.param_va) {
+ svc_gl.param_va = ((u64)(v[0] & 0xff) << 32) |
+ (u64)(v[1] & 0xfffffffc);
+ svc_gl.param_size = v[2]; /* observed 0x10 */
+ }
+ return;
+ case 0x155c: /* SET_TEX_SAMPLER_POOL_A/B/C: [1 214fa200 0] */
+ if (count >= 3)
+ svc_gl_add_ptr(((u64)(v[0] & 0xff) << 32) |
+ (u64)(v[1] & 0xfffffffc));
+ return;
+ case 0x0f84: /* SET_VERTEX_STREAM_SUBSTITUTE_A/B: [1 21200000] */
+ if (count >= 2)
+ svc_gl_add_ptr(((u64)(v[0] & 0xff) << 32) |
+ (u64)(v[1] & 0xfffffffc));
+ return;
+ case 0x0180: /* LINE_LENGTH_IN run: VALUE, LINE_COUNT,
+ * OFFSET_OUT_UPPER, OFFSET_OUT, PITCH_OUT.
+ * Observed: [0000000c 1 1 214f8f00 0000000c].
+ */
+ if (count >= 4)
+ svc_gl_add_ptr(((u64)(v[2] & 0xff) << 32) |
+ (u64)(v[3] & 0xfffffffc));
+ return;
+ case 0x01b0: /* LAUNCH_DMA + LOAD_INLINE_DATA (op3/op5): the run's
+ * data words ARE the observed upload payload. Keep the
+ * FIRST run's bytes for the M2-S1 inline attachment.
+ * Observed: a004006c -> [00000041 00000670 00000690
+ * 000006b0].
+ */
+ if (!svc_gl.blob_len && dlen) {
+ u32 n = dlen < sizeof(svc_gl.blob) ?
+ dlen : (u32)sizeof(svc_gl.blob);
+
+ memcpy(svc_gl.blob, data, n);
+ svc_gl.blob_len = n;
+ }
+ return;
+ default:
+ return;
+ }
+}
+
+/*
+ * Close the open section: synthesize the QMD from the collected fields and
+ * capture it as the forwarding candidate. The QMD word layout mirrors
+ * svc_gr_qmd_decode() (the CUDA bridge contract): 48/49 program, 32/33
+ * parameter + size, 23..25 release, 34..47 pointer pairs, qmd[4] b10
+ * REL_ENABLE. Every VA is copied from a decoded operand; qmd_dev_va stays 0
+ * (synthesized - no QMD buffer exists in guest memory) so the backend uses
+ * its qmdwin/scratch path.
+ */
+static void svc_gl_flush(struct svc_channel *ch,
+ const struct svc_push_state *st, const u8 *buf,
+ u32 len, u64 push_va, bool trusted, bool replay,
+ u32 at_off)
+{
+ struct svc_push_state s2;
+ struct gsp_bridge_inline pr;
+ u32 n_recs = 0, k;
+
+ if (!svc_gl.seen || !svc_gl.prog_va || !svc_gl.param_va ||
+ !svc_gl.rel_va || !trusted)
+ goto out;
+ /*
+ * SESSION 149 R15 (M1.1a): admit a rewind replay when the same slot
+ * re-read valid bytes whose content hash matches the recorded pass
+ * (the pump sets cap_trust only for such a hash-verified replay; see
+ * the trust admission at the decode call site). The session-wide
+ * (push_va, hash) capture history is the exactly-once guard: a push
+ * already captured/forwarded makes every later replay a no-op.
+ */
+ if (replay && svc_gr_cand_push_seen(push_va, svc_push_hash(buf, len))) {
+ if (svc_gl_rep_log < 16) {
+ svc_gl_rep_log++;
+ pr_info("sema-gl: replay already captured h=0x%x push=0x%llx (no re-capture)\n",
+ ch->h_object, push_va);
+ }
+ goto out;
+ }
+ s2 = *st;
+ memset(s2.qmd, 0, sizeof(s2.qmd));
+ s2.qmd[48] = (u32)svc_gl.prog_va;
+ s2.qmd[49] = ((u32)(svc_gl.prog_va >> 32)) & 0x1ffff;
+ s2.qmd[32] = (u32)svc_gl.param_va;
+ s2.qmd[33] = (((u32)(svc_gl.param_va >> 32)) & 0x1ffff) |
+ ((svc_gl.param_size >> 4) << 19);
+ s2.qmd[23] = (u32)svc_gl.rel_va;
+ s2.qmd[24] = ((u32)(svc_gl.rel_va >> 32)) & 0xff;
+ s2.qmd[25] = svc_gl.rel_payload;
+ s2.qmd[4] |= 1u << 10; /* REL_ENABLE */
+ /*
+ * qmd[24] b31 (REL_ONE_WORD) stays clear on the first launch: the
+ * backend then redirects release0 to the module semaphore and the
+ * sema service authors the guest word (set it once rel_hpa resolving
+ * is wanted). qmd[24] b26 (REDUCTION) likewise stays clear.
+ */
+ for (k = 0; k < svc_gl.n_ptr && k < SVC_GR_POINTER_MAX - 1; k++) {
+ s2.qmd[34 + 2 * k] = (u32)svc_gl.ptr[k];
+ s2.qmd[35 + 2 * k] = ((u32)(svc_gl.ptr[k] >> 32)) & 0x1ffff;
+ }
+ s2.qmd_dev_va = 0;
+ s2.qmd_hdr = 0;
+ s2.qmd_end = 0;
+ s2.qmd_have = 0;
+ /*
+ * SESSION 149 R15 (M2-S1): attach the observed LAUNCH_DMA /
+ * LOAD_INLINE_DATA payload as an inline record at the synthesized
+ * program VA. The GL program page (0x121201b00) is NOT among the
+ * section's own upload destinations, so without this the backend's
+ * w48 code-source screen sees an empty page, withdraws to the guest
+ * VA and the launch dies at FAULT_PDE; with it the proven win0
+ * shadow copy + w48/49 rewrite line runs (the short blob is
+ * expected to fault in the SM later - that is the next wall, not
+ * this one).
+ */
+ if (svc_gl.blob_len) {
+ memset(&pr, 0, sizeof(pr));
+ pr.dst_va = svc_gl.prog_va;
+ pr.len = svc_gl.blob_len;
+ memcpy(pr.data, svc_gl.blob, pr.len);
+ n_recs = 1;
+ }
+ pr_info("sema-gl: section captured h=0x%x push=0x%llx len=%u off=0x%x prog=0x%llx param=0x%llx/0x%x rel=0x%llx/%u ptr=%u blob=%u replay=%u\n",
+ ch->h_object, push_va, len, at_off, svc_gl.prog_va,
+ svc_gl.param_va, svc_gl.param_size, svc_gl.rel_va,
+ svc_gl.rel_payload, svc_gl.n_ptr, svc_gl.blob_len,
+ replay ? 1u : 0u);
+ svc_gr_cand_capture(ch, &s2, n_recs ? &pr : NULL, n_recs, buf, len,
+ push_va);
+out:
+ /*
+ * SESSION 149 R15 (M1.1a): preserve the last valid release across
+ * the reset - it belongs to the channel (decoded from the bracketing
+ * 24 B release pushes), not to this section; wiping it here and at
+ * the section open starved the flush guard of rel_va on the trusted
+ * first pass (the r883/r886 one-shot decode).
+ */
+ {
+ u64 keep_rel = svc_gl.rel_va;
+ u32 keep_pay = svc_gl.rel_payload;
+
+ memset(&svc_gl, 0, sizeof(svc_gl));
+ svc_gl.rel_va = keep_rel;
+ svc_gl.rel_payload = keep_pay;
+ }
+}
+
+/*
* Consume the current GR candidate without forwarding it: hand the launch to
* the host CUDA bridge when that path is enabled, then clear the candidate.
* Exactly-once via `offered`. Called on the service thread (capture/refusal)
@@ -11445,6 +11706,57 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
continue;
}
+ /*
+ * SESSION 149 R14 (sema_gl_xlate): GL/3D direct-stream section
+ * recognition. A SET_OBJECT (op 1, addr 0, one class word)
+ * binds a class to a subchannel; C597 (TURING_A, the observed
+ * GL class) on the channel subchannel opens the section. Any
+ * other class bind closes it (the copy-class C5B5 and 2D 902D
+ * binds surrounding the GL push must not open sections). The
+ * collected VA operands live in svc_gl until the section closes
+ * at the end of the pass or at the next class bind.
+ */
+ if (gsp_sema_gl_xlate && op == 1 && addr == 0 && count == 1 &&
+ off + 8 <= len) {
+ u32 cls;
+
+ memcpy(&cls, buf + off + 4, 4);
+ if (cls == 0xc597) {
+ /*
+ * SESSION 149 R15 (M1.1a): carry the last
+ * valid release across the section reset.
+ * It was decoded from the bracketing 24 B
+ * release pushes BEFORE this class bind;
+ * the old wipe-and-open here left rel_va
+ * at 0 at flushtime, so the trusted first
+ * pass of the one-shot setup push was
+ * rejected by the flush guard and the
+ * section was never captured (r883/r886:
+ * exactly one trusted decode of the 1524 B
+ * push, zero captures).
+ */
+ u64 keep_rel = svc_gl.rel_va;
+ u32 keep_pay = svc_gl.rel_payload;
+
+ if (svc_gl.seen)
+ svc_gl_flush(ch, &st, buf, len,
+ push_va, trusted, replay,
+ off);
+ memset(&svc_gl, 0, sizeof(svc_gl));
+ svc_gl.seen = true;
+ svc_gl.subch = subch;
+ svc_gl.rel_va = keep_rel;
+ svc_gl.rel_payload = keep_pay;
+ } else if (svc_gl.seen) {
+ svc_gl_flush(ch, &st, buf, len, push_va,
+ trusted, replay, off);
+ }
+ } else if (gsp_sema_gl_xlate && svc_gl.seen &&
+ subch == svc_gl.subch) {
+ svc_gl_field(addr, count, buf + off + 4,
+ len - off - 4);
+ }
+
if (op == 3 || op == 5) {
/*
* NON_INC / ONE_INC methods carry their own data
@@ -11594,6 +11906,15 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
svc.pushes_seen++;
st.rel_va = va;
st.rel_payload = payload;
+ /* SESSION 149 R14: keep the last VALID release
+ * decoded on this channel for the GL section
+ * synthesizer (the 24 B release pushes bracket
+ * the large GL launch push in ring order).
+ */
+ if (gsp_sema_gl_xlate) {
+ svc_gl.rel_va = va;
+ svc_gl.rel_payload = payload;
+ }
svc_wait_rel_va = va;
svc_wait_rel_payload = payload;
svc_wait_rel_off = off;
@@ -13309,6 +13630,13 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
off += 4 + count * 4;
}
+ /*
+ * SESSION 149 R14: close an open GL/3D section when the pass ends -
+ * this is the normal capture point (one section per large GL push).
+ */
+ if (gsp_sema_gl_xlate && svc_gl.seen)
+ svc_gl_flush(ch, &st, buf, len, push_va, trusted, replay, off);
+
if (gsp_sema_dbg && ch->h_object &&
svc.entry_log < 16384) {
svc.entry_log++;
@@ -16992,6 +17320,10 @@ static bool svc_gr_ram_ring_scan(struct nv_vgpu_device *vgpu,
svc.chan[i].gr_ram_cursor = ch->gr_ram_cursor;
svc.chan[i].gr_ram_passes = ch->gr_ram_passes;
svc.chan[i].gr_ram_logged = ch->gr_ram_logged;
+ /* SESSION 149 R15: the M1.1b keep-alive budget state. */
+ svc.chan[i].gr_ram_kick = ch->gr_ram_kick;
+ svc.chan[i].gr_ram_refreshes = ch->gr_ram_refreshes;
+ svc.chan[i].gr_ram_refresh_at = ch->gr_ram_refresh_at;
break;
}
}
@@ -27392,6 +27724,33 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
svc_notify2d_keepalive(vgpu, ch);
/*
+ * SESSION 149 R15 (M1.1b): GR RAM-scan keep-alive. The boot
+ * budget can retire before the client creates its ring (r886:
+ * 16 slices spent, no pairing). A GPFIFO put advance proves
+ * the client is live NOW, so grant a fresh bounded budget -
+ * capped and spaced so an unfound ring cannot keep the scan
+ * hot. The scan itself stops on its own once the ring is
+ * content-validated (gr_ram_ring).
+ */
+ if (!ch->engine_type && ch->h_object != 0x31415900u &&
+ ch->gr_index < 32 &&
+ !test_bit(ch->gr_index, &svc_gr_ring_done) &&
+ ch->gr_ram_passes >= SVC_GR_RAM_PASS_MAX &&
+ ch->gr_ram_refreshes < SVC_GR_RAM_REFRESH_MAX &&
+ time_after_eq(jiffies, ch->gr_ram_refresh_at) &&
+ ch->gr_ram_kick != put) {
+ ch->gr_ram_kick = put;
+ ch->gr_ram_refreshes++;
+ ch->gr_ram_refresh_at = jiffies +
+ msecs_to_jiffies(SVC_GR_RAM_REFRESH_MS);
+ ch->gr_ram_passes = 0;
+ pr_info("sema-chan: GR ring h=0x%x rank=%u RAM content scan keep-alive %u/%u (put=%u moved; budget reset)\n",
+ ch->h_object, ch->gr_index,
+ ch->gr_ram_refreshes, SVC_GR_RAM_REFRESH_MAX,
+ put);
+ }
+
+ /*
* ISSUE-0002 diag: put snapshots for CE channels, bounded per
* session. The throttle is indexed by rank (the channel struct
* iterated here is a local copy, so a per-channel stamp never
@@ -28341,13 +28700,57 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
pr_info("vgsp-gr: GR rehold capture idx=%llu va=0x%llx\n",
(unsigned long long)idx, va);
}
- if (!cap_trust && !entry_replay &&
+ /*
+ * SESSION 149 R15
+ * (M1.1a): a rewind
+ * replay whose slot
+ * identity AND content
+ * hash both match the
+ * recorded pass is the
+ * same push re-read
+ * (entry words alone
+ * cannot tell it from a
+ * rewritten push - the
+ * hash can, and the
+ * r354 checks above
+ * cleared entry_replay
+ * on every mismatch, so
+ * a surviving replay
+ * plus the explicit hash
+ * compare here is the
+ * verified case).
+ * Admit it as trusted so
+ * the GL section /
+ * synthesis capture can
+ * still be made when the
+ * first pass never
+ * captured (the r883
+ * one-shot setup push
+ * decoded exactly once,
+ * as a replay, and the
+ * old suppression threw
+ * that single chance
+ * away). Ops stay
+ * suppressed:
+ * entry_replay keeps
+ * them off at the
+ * decode call, and the
+ * capture sites hold
+ * their own exactly-once
+ * guards.
+ */
+ if (!cap_trust &&
!ch->engine_type &&
gsp_phys_gr_forward_enabled() &&
!unreadable &&
svc_method_stream_plausible(pb,
- len))
- cap_trust = true;
+ len)) {
+ if (!entry_replay ||
+ (entry_ident &&
+ ch->slot_ops_hash[idx] ==
+ svc_push_hash(pb, len)))
+ cap_trust = true;
+ }
svc_entry_outcome("decode", ch,
idx, va, len);
@@ -29941,6 +30344,12 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
svc.chan[k].gr_ram_cursor = ch->gr_ram_cursor;
svc.chan[k].gr_ram_passes = ch->gr_ram_passes;
svc.chan[k].gr_ram_logged = ch->gr_ram_logged;
+ /* SESSION 149 R15: M1.1b keep-alive state. */
+ svc.chan[k].gr_ram_kick = ch->gr_ram_kick;
+ svc.chan[k].gr_ram_refreshes =
+ ch->gr_ram_refreshes;
+ svc.chan[k].gr_ram_refresh_at =
+ ch->gr_ram_refresh_at;
svc.chan[k].gr_ram_ring = ch->gr_ram_ring;
svc.chan[k].userd_scans = ch->userd_scans;
svc.chan[k].notify2d_va = ch->notify2d_va;