summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-09 14:59:41 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-09 14:59:41 -0400
commit12c52b35252d8f46db1b7294ec8439530e4b71b9 (patch)
tree99545bf50ec44231a6f23a694ecde354937480b8 /kernel
parent088fa8f3e854ff33fe2d1188d2d237942956b918 (diff)
downloadopen-iov-12c52b35252d8f46db1b7294ec8439530e4b71b9.tar.gz
open-iov-12c52b35252d8f46db1b7294ec8439530e4b71b9.zip
vgsp-sema: CE USERD is layout-only; never latch the registered stale block (ISSUE-0002)
The pump calls svc_chan_userd before the ring is pinned; the old candidate list then accepted the registered pool-relative userdMem offset (stale cross-session 1/1) and userd_ok froze it for the session (r42 c2 rank0 userd=0xf0000 while the layout block 0x90000 is the one the guest writes). For CE channels: wait for the ring, validate its entry0 (a CE push VA + len), then accept the layout USERD at ring+0x10000 even while idle; anything else returns -ENOENT so the next pass retries. Registered-offset candidates remain for non-CE channels.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c95
1 files changed, 49 insertions, 46 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index 4cc1624..07aa8fa 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -7715,56 +7715,59 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
: SVC_APERTURE_FB;
/*
- * ISSUE-0002 (r40): prefer the layout-derived CE USERD and accept it
- * while it is still idle. In a second session the registered userdMem
- * offset (pool-relative, see below) aliases a DIFFERENT rank's real
- * USERD whose stale put/get from the previous session won the
- * coherent-pair probe while this channel's true block was still 0/0:
- * c2 rank0 read rank3's stale 1/1 at FB 0xf0000 and the pump never
- * followed rank0's own GP_PUT. The true CE USERD sits at
- * ring + 0x10000 in the ring's aperture - confirmed by the guest
- * CPU mapping of gpFifoGpuVa (GPU VA gpfifo+0x20000 maps to BAR
- * offset ring+0x10000) and by every CE rank that resolved correctly.
- * An idle (0/0) read is accepted here because the guest writes the
- * block on the channel's first push; only unreadable or incoherent
- * candidates fall through to the old list.
+ * ISSUE-0002 (r40/r42): CE USERD selection is layout-driven and must
+ * not fall back to the registered userdMem offset. That offset is
+ * pool-relative (see below) and in a second session it aliases a
+ * DIFFERENT rank's real USERD whose stale put/get from the previous
+ * session wins the coherent-pair probe while this channel's true
+ * block is still idle: c2 rank0 read rank3's stale 1/1 at FB 0xf0000
+ * and the pump never followed rank0's own GP_PUT (r40/r42). The true
+ * CE USERD sits at ring + 0x10000 in the ring's aperture - confirmed
+ * by the guest CPU mapping of gpFifoGpuVa (GPU VA gpfifo+0x20000 maps
+ * to BAR offset ring+0x10000) and by every CE rank that resolved
+ * correctly.
*
- * The ring itself must validate first (entry0 = a CE push VA + len,
- * same gate as svc_ring_autopin): r41 showed svc_lookup can answer a
- * fresh gpfifo VA with an unrelated FB offset (rank4 -> 0x90000), and
- * an idle acceptance on that bogus base cemented the wrong USERD.
- */
- if (ring_pa && ch->engine_type != 0) {
+ * Ordering trap: this function is called on passes BEFORE the ring is
+ * pinned, and the old list then accepted the stale registered block.
+ * For CE channels therefore: no ring -> keep waiting; ring must
+ * validate (entry0 = a CE push VA + len, the same gate as
+ * svc_ring_autopin); then the layout USERD may be accepted while
+ * still idle (0/0) because the guest writes it on the first push.
+ * Any other outcome returns -ENOENT so the pump retries next pass -
+ * never the registered candidate.
+ */
+ if (ch->engine_type != 0) {
u8 e[SVC_GPFIFO_ENTRY_SIZE];
- u32 e0, e1, len;
+ u32 e0, e1, len, p = 0, g = 0;
u64 va;
- bool ring_ok = false;
+ int rc;
- if (!svc_read_ap(vgpu, ring_pa, ring_ap, e, sizeof(e))) {
- memcpy(&e0, e, 4);
- memcpy(&e1, e + 4, 4);
- va = ((u64)(e1 & 0xff) << 32) |
- (u64)(e0 & 0xfffffffc);
- len = ((e1 >> 10) & 0x1fffff) << 2;
- ring_ok = !(va & 0xfffff) &&
- va >= 0x120000000ULL && va < 0x121000000ULL &&
- len >= 4 && len <= 0x10000;
- }
- if (ring_ok) {
- u32 p = 0, g = 0;
- int rc = svc_userd_probe(vgpu, ring_pa + 0x10000,
- ring_ap, ch->gpfifo_entries,
- &p, &g);
-
- if (rc == 0 || rc == -EAGAIN) {
- ch->userd_pa = ring_pa + 0x10000;
- ch->userd_as = ring_ap;
- ch->userd_ok = true;
- *put = p;
- *get = g;
- return 0;
- }
- }
+ if (!ring_pa)
+ return -ENOENT;
+ /*
+ * svc_lookup can answer a fresh gpfifo VA with an
+ * unrelated FB offset (r41 rank4 -> 0x90000); validate the
+ * ring content before deriving anything from it.
+ */
+ if (svc_read_ap(vgpu, ring_pa, ring_ap, e, sizeof(e)))
+ return -ENOENT;
+ memcpy(&e0, e, 4);
+ memcpy(&e1, e + 4, 4);
+ va = ((u64)(e1 & 0xff) << 32) | (u64)(e0 & 0xfffffffc);
+ len = ((e1 >> 10) & 0x1fffff) << 2;
+ if ((va & 0xfffff) || va < 0x120000000ULL ||
+ va >= 0x121000000ULL || len < 4 || len > 0x10000)
+ return -ENOENT;
+ rc = svc_userd_probe(vgpu, ring_pa + 0x10000, ring_ap,
+ ch->gpfifo_entries, &p, &g);
+ if (rc && rc != -EAGAIN)
+ return -ENOENT;
+ ch->userd_pa = ring_pa + 0x10000;
+ ch->userd_as = ring_ap;
+ ch->userd_ok = true;
+ *put = p;
+ *get = g;
+ return 0;
}
if (ring_pa) {