summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-12 16:22:16 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-12 16:22:16 -0400
commit54a8f7b3385cccedac3f74a73ae9bc04089203d0 (patch)
tree906d408c66e0da5a422e793db07856c24a8772e6 /kernel/gsp_sema_service.c
parentf3cd10e0bdf5f4379c57f048d7e589612f8ac6e1 (diff)
downloadopen-iov-54a8f7b3385cccedac3f74a73ae9bc04089203d0.tar.gz
open-iov-54a8f7b3385cccedac3f74a73ae9bc04089203d0.zip
vgsp-sema: reject all-FF continuation chunks in the CE push read; try the displaced pin pair
The r129 cross-page evidence: a 216-byte CE push whose SET_SEMAPHORE_A + LAUNCH_DMA tail fell in the next 4 KB page, whose injected pin resolved to an all-0xFF page while the first page decoded perfectly. A continuation chunk read from an unvalidated source (injected pin, its displaced pair, or the linear window guess) is now rejected when the whole chunk is 0xFF, the displaced ipin-alt pair is tried as a new source, and a bounded line names the rejected (va, pa, src) at the fix site.
Diffstat (limited to 'kernel/gsp_sema_service.c')
-rw-r--r--kernel/gsp_sema_service.c66
1 files changed, 59 insertions, 7 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 45a9843..20dfc54 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -7980,6 +7980,8 @@ static bool svc_push_prefix_ok(const u8 *buf, size_t len)
/* Fallback-line budget for the whole boot. */
static u32 svc_pushpg_fb_log;
+/* Bounded split-read rejection lines (cross-page CE push, r129 class). */
+static u32 svc_pushpg_split_log;
/*
* Read a push the way the engine does: every 4 KB page of the range is
@@ -7999,11 +8001,16 @@ static u32 svc_pushpg_fb_log;
* method stream is rejected and the remaining candidates are tried
* (observed: a wrong injected pin for the push page made every push
* decode no release, starving the client's tracker);
- * 2. validated self-pin (svc_pin_lookup_valid): read-back-validated pages
+ * 2. the displaced injected pair (svc_ipin_alt_lookup): what the page
+ * resolved to before a later injection overwrote the primary slot -
+ * the fall-back when a foreign/stale injection shadowed a good page
+ * (observed r129: a continuation page of a cross-page CE push under
+ * an all-FF pin);
+ * 3. validated self-pin (svc_pin_lookup_valid): read-back-validated pages
* (content rescue, first-push pairing), window guesses excluded;
- * 3. the channel's linear window mapping (svc_pb_win_lookup): last resort
+ * 4. the channel's linear window mapping (svc_pb_win_lookup): last resort
* for a page no validated source knows;
- * 4. outside any window: the remaining trusted sources
+ * 5. outside any window: the remaining trusted sources
* (svc_lookup_trusted), exactly the old behaviour for GR/other pushes.
*
* For a contiguous allocation every path resolves to the same PA the old
@@ -8031,8 +8038,9 @@ static int svc_read_va_push_ex(struct nv_vgpu_device *vgpu,
have_win = !svc_pb_win_lookup(ch, page_va, &win_pa);
- for (src = 0; src < 4 && !done; src++) {
+ for (src = 0; src < 5 && !done; src++) {
bool via_ipin = false;
+ bool untrusted = false;
pa = 0;
ap = SVC_APERTURE_SYS;
@@ -8042,22 +8050,39 @@ static int svc_read_va_push_ex(struct nv_vgpu_device *vgpu,
svc_ipin_lookup(va, &pa, &ap))
continue;
via_ipin = true;
+ untrusted = true;
if (have_win)
svc_pushpg_note(ch, page_va, pa,
win_pa);
break;
case 1:
+ /*
+ * Displaced injected pin (svc_ipin_alt):
+ * the mapping this page had before a later
+ * injection overwrote it. The push decode
+ * is the consumer here, so a pin that no
+ * longer reads like the page's validated
+ * content (all-FF continuation chunks,
+ * see below) can fall back to the pair the
+ * current injection displaced.
+ */
+ if (svc_ipin_alt_lookup(va, &pa, &ap))
+ continue;
+ untrusted = true;
+ break;
+ case 2:
if (svc_pin_lookup_valid(va, &pa, &ap))
continue;
if (have_win)
svc_pushpg_note(ch, page_va, pa,
win_pa);
break;
- case 2:
+ case 3:
if (!have_win)
continue;
pa = win_pa + (va & (SEMA_PAGE_SIZE - 1));
ap = SVC_APERTURE_SYS;
+ untrusted = true;
break;
default:
/* learned cache / discovered map / page
@@ -8083,18 +8108,45 @@ static int svc_read_va_push_ex(struct nv_vgpu_device *vgpu,
!svc_push_prefix_ok(p, chunk))
continue; /* content says: wrong pin */
/*
+ * A continuation chunk (not the push start) read from
+ * an unvalidated source can be a stale/foreign pin:
+ * observed r129, a 216-byte CE push whose last 24
+ * bytes (the SET_SEMAPHORE_A + LAUNCH_DMA) fell in a
+ * page whose injected pin resolved to an all-0xFF
+ * page while the first page was correct. A full
+ * chunk of 0xFF is never a method stream - fresh
+ * emulation pages read 0xFF - so reject it and try
+ * the remaining sources (the displaced alt pair
+ * first). The bounded line names the rejected
+ * (va, pa, src) for the post-mortem.
+ */
+ if (untrusted && !first && chunk >= 64 &&
+ !memchr_inv(p, 0xff, chunk)) {
+ if (svc_pushpg_split_log < 8) {
+ svc_pushpg_split_log++;
+ pr_info("sema-pushpg: split reject va=0x%llx pa=0x%llx src=%s (all-FF) at page 0x%llx\n",
+ va, pa,
+ src == 0 ? "ipin" :
+ (src == 1 ? "ipin-alt" :
+ "win"),
+ page_va);
+ }
+ last_rc = -EIO;
+ continue;
+ }
+ /*
* ISSUE-0002 (r51): a window guess that reads ALL
* ZEROS cannot be right - the paired base page is
* real, so a zero first chunk means the linear window
* does not describe this page (r49: the second
* session's CE push pages read zeros and, because the
* read "succeeded", shadowed the per-page resolvers).
- * Fall through to src=3 instead. Non-zero window
+ * Fall through to src=4 instead. Non-zero window
* content stays trusted exactly as before (r50:
* requiring method-stream plausibility rejected valid
* non-method push prefixes and corrupted c1).
*/
- if (src == 2 && first && !memchr_inv(p, 0, chunk))
+ if (src == 3 && first && !memchr_inv(p, 0, chunk))
continue;
done = true;
}