summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-28 16:02:21 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-28 16:02:21 -0400
commitbea420425bd67fbd2b7455bbb0467c979df0debc (patch)
tree5c4f5e10d6309821f71c58aea37b22678100e450 /kernel/gsp_sema_service.c
parente4a3d3a4ad799322d92d41a2b5bd447ebdb35e07 (diff)
downloadopen-iov-bea420425bd67fbd2b7455bbb0467c979df0debc.tar.gz
open-iov-bea420425bd67fbd2b7455bbb0467c979df0debc.zip
sema: per-push release/ops summary; never run work from rescued pages
Log one line per ring-decoded push (channel, engine, length, op-run count, decoded release VA/payload, last 24 bytes) to make the push->tracker path observable; it showed that the content rescue had been pinning unrelated RAM pages: pushes of length 4196/8500/12700 whose tails are RISC-V code (ecall/jal) - GSP firmware or other code pages whose bytes matched the expected release pattern. Those pages decode as plausible but bogus method streams, so work executed from them can write garbage into vidmem. Rescued pages now apply the release only (allow_ops=false); work requires a page read through a trusted translation.
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c45
1 files changed, 44 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 0578d3c..5505c1e 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -313,6 +313,7 @@ struct sema_svc {
u64 memsets_fail;
u64 ring_ops; /* op runs from ring-decoded pushes */
u64 lda_log; /* LAUNCH_DMA inventory budget */
+ u64 entry_log; /* per-push summary budget */
u64 releases_seen;
u64 releases_applied;
u64 releases_missed; /* no VA->PA entry */
@@ -1545,6 +1546,9 @@ struct svc_push_state {
u32 sem_inc;
u32 rs_upper, rs_lower, rs_payload;
u32 have_rs_addr, have_rs_payload;
+ u64 rel_va; /* last release decoded in this push */
+ u32 rel_payload;
+ u32 have_rel;
};
/* ------------------------------------------------------------------ */
@@ -1725,6 +1729,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
struct svc_push_state st;
struct svc_memset_op ops[SVC_MAX_MEMSETS];
u32 n_ops = 0;
+ u32 ops_runs = 0;
u32 off = 0;
memset(&st, 0, sizeof(st));
@@ -1825,11 +1830,15 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
if (page_pa)
svc_mark_hot(page_pa);
svc.pushes_seen++;
+ st.rel_va = va;
+ st.rel_payload = payload;
+ st.have_rel = 1;
/* The push's work always runs; see the
* REPORT_SEM comment below. */
if (allow_ops && n_ops) {
svc_run_ops(vgpu, ops, n_ops);
svc.ring_ops++;
+ ops_runs++;
}
n_ops = 0;
if (!svc_sem_read(vgpu, va, &cur) &&
@@ -1889,6 +1898,9 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
if (page_pa)
svc_mark_hot(page_pa);
svc.pushes_seen++;
+ st.rel_va = va;
+ st.rel_payload = st.rs_payload;
+ st.have_rel = 1;
/*
* The push's collected work always runs on
* real hardware; the semaphore release only
@@ -1907,6 +1919,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
if (allow_ops && n_ops) {
svc_run_ops(vgpu, ops, n_ops);
svc.ring_ops++;
+ ops_runs++;
}
n_ops = 0;
if (svc_sem_read(vgpu, va, &cur))
@@ -2044,6 +2057,9 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
svc.pushes_seen++;
sem_va = ((u64)st.sem_va_hi << 32) |
st.sem_va_lo;
+ st.rel_va = sem_va;
+ st.rel_payload = st.sem_payload;
+ st.have_rel = 1;
if (st.have_sem && st.sem_payload &&
sem_va >= SEMA_VA_LO && sem_va < SEMA_VA_HI) {
@@ -2067,6 +2083,7 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
if (allow_ops && n_ops) {
svc_run_ops(vgpu, ops, n_ops);
svc.ring_ops++;
+ ops_runs++;
}
if (pending) {
svc.pushes_pending++;
@@ -2090,6 +2107,21 @@ static void svc_decode_stream(struct nv_vgpu_device *vgpu, const u8 *buf,
}
off += 4 + count * 4;
}
+
+ if (ch_h && svc.entry_log < 64) {
+ svc.entry_log++;
+ {
+ u8 tail[24];
+ u32 tlen = len >= sizeof(tail) ? sizeof(tail) : len;
+
+ if (tlen)
+ memcpy(tail, buf + len - tlen, tlen);
+ pr_info("sema-push: h=0x%x eng=%u len=%u ops_runs=%u rel=0x%llx pay=%u have_rel=%u tail=%*phN\n",
+ ch_h, ch_eng, len, ops_runs, st.rel_va,
+ st.rel_payload, st.have_rel, tlen,
+ tlen ? tail : NULL);
+ }
+ }
}
/* ------------------------------------------------------------------ */
@@ -3278,9 +3310,20 @@ static void svc_pump_channels(struct nv_vgpu_device *vgpu)
/* Rescue succeeded, retry the read. */
if (!svc_read_va_trusted(vgpu, va, pb,
len)) {
+ /*
+ * Never run work decoded from a
+ * rescued page: the rescue matches
+ * the expected release bytes in
+ * arbitrary RAM and has matched GSP
+ * firmware/code pages, whose bytes
+ * decode as plausible but bogus
+ * method streams (ops_runs could
+ * fill vidmem with garbage). Only
+ * the release is applied.
+ */
svc_decode_stream(vgpu, pb,
len, 0,
- ch->engine_type != 0,
+ false,
ch->h_object,
ch->engine_type);
ch->submissions++;