diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-12 01:29:13 -0500 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-11-12 01:29:13 -0500 |
| commit | fa985e759707ce011bd238bbbb73bc422fccb90f (patch) | |
| tree | 70c2b7956e3e5efaf001a02da173fc6df75ddfd6 /kernel/gsp_sema_service.c | |
| parent | fc01d736909bfaa411643eddbe1593a78c83371a (diff) | |
| download | open-iov-fa985e759707ce011bd238bbbb73bc422fccb90f.tar.gz open-iov-fa985e759707ce011bd238bbbb73bc422fccb90f.zip | |
vgsp: resolve GSP-client USERD from hUserdMemory and skip foreign USERD pages
GSP-client kernel channels carry their USERD as hUserdMemory[subdev]
(NV_CHANNEL_ALLOC_PARAMS @32) plus userdOffset[subdev] (@64), leaving the
userdMem memdesc (@168) zero. The service therefore adopted another live
channel's USERD page (c23: h=0x1000013 took the RC watchdog h=0x31415900's
block at fb 0x8f0000 every pass) and the Xorg PB progress wait never
advanced.
Remember client memory-object ALLOCs (class 0x3e sysmem, 0x40 vidmem;
0x70/0x50a0 are virtual ranges and are refused) in a bounded
(hClient,hObject) table, alias them on DUP_OBJECT and retire them on FREE.
At channel registration, if the wire userdMem base is zero, resolve
hUserdMemory+userdOffset through that table and set userd_pa/userd_as only
when the base is nonzero, page-aligned and in bounds; otherwise fail closed
with a rate-limited reason. Also skip FB-sweep USERD candidates on a page
already owned by another live channel.
Validation pending a fresh V30 cycle: glxinfo -B exit 0, Xorg WAIT count 0,
chan_dump h=0x1000013 userd!=0 ok=1 get advancing, sema-push have_rel=1,
glxgears FPS unchanged, GZDoom -glversion 4.0 past V_Init.
Evidence: handoff-meta-plan.md CONT.438; c23 X/GLX logs; ABI
gsp_abi_check.c:1764, nvos.h:1631-1668, cl003e.h/cl0040.h.
Diffstat (limited to 'kernel/gsp_sema_service.c')
| -rw-r--r-- | kernel/gsp_sema_service.c | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c index 6da812d..146291c 100644 --- a/kernel/gsp_sema_service.c +++ b/kernel/gsp_sema_service.c @@ -26747,6 +26747,12 @@ static bool svc_ce_declared_userd(struct nv_vgpu_device *vgpu, return true; } +/* + * CONT.438: bounded witness for FB-sweep candidates skipped because another + * live channel already owns their page. + */ +static u32 svc_foreign_userd_skip_log; + static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch, u64 ring_pa, int ring_ap, u32 *put, u32 *get, int rrc) { @@ -27214,11 +27220,46 @@ ce_fb_scan: bool wtry = false, wused = false; u32 woff = (u32)(ch->gpfifo_va & (SEMA_PAGE_SIZE - 1)); + /* + * CONT.438 (patch A): a candidate on a 4K page that another + * live channel already owns is not this channel's USERD. The + * live X/GLX channel 0x1000013 re-adopted the RC watchdog + * channel 0x31415900's block at fb 0x8f0000 every pass (its + * own USERD is client-allocated, so the wire userdMem is + * zero); the foreign pair then never matched the client's + * progress. Snapshot the other channels' USERD pages once per + * sweep and refuse their pages as candidates. Failing closed + * here is deliberate: a foreign block must not become the + * write target for GP_GET. + */ + u64 foreign_userd_pages[SVC_MAX_CHANNELS]; + unsigned long chflags; + u32 foreign_userd_n = 0; + u32 oi; + + spin_lock_irqsave(&svc.chan_lock, chflags); + for (oi = 0; + oi < SVC_MAX_CHANNELS && + foreign_userd_n < SVC_MAX_CHANNELS; oi++) { + struct svc_channel *other = &svc.chan[oi]; + + if (!other->valid || other->vgpu != vgpu || + !other->userd_pa) + continue; + if (other->h_object == ch->h_object && + other->vgpu == ch->vgpu) + continue; + foreign_userd_pages[foreign_userd_n++] = + other->userd_pa & ~0xfffULL; + } + spin_unlock_irqrestore(&svc.chan_lock, chflags); + ch->fb_userd_scan_at = jiffies; ch->fb_userd_scan_n++; ch->userd_scans++; ring_sweep_ran = true; - lim = min_t(u64, svc_fb_shadow_size(vgpu), 0x20000000ULL); + lim = min_t(u64, svc_fb_shadow_size(vgpu), + 0x20000000ULL); if (base && lim) { for (off = 0; off + 0xa0 <= lim; off += 0x200) { u32 hp, hg; @@ -27230,6 +27271,8 @@ ce_fb_scan: int rck = -1; u64 rkva = 0; u32 rklen = 0; + u64 page; + bool foreign = false; memcpy(&hp, base + off + SVC_USERD_GP_PUT, 4); memcpy(&hg, base + off + SVC_USERD_GP_GET, 4); @@ -27246,6 +27289,27 @@ ce_fb_scan: ch->gpfifo_entries <= 1024))) continue; gate_n++; + /* + * CONT.438: the page-ownership gate. A block + * on another live channel's USERD page cannot + * be this channel's control block. + */ + page = off & ~0xfffULL; + for (oi = 0; oi < foreign_userd_n; oi++) { + if (foreign_userd_pages[oi] == page) { + foreign = true; + break; + } + } + if (foreign) { + if (svc_foreign_userd_skip_log < 16) { + svc_foreign_userd_skip_log++; + pr_info("sema-chan: userdp h=0x%x skip fb 0x%llx (page owned by another live channel; put=%u get=%u)\n", + ch->h_object, off, hp, + hg); + } + continue; + } /* Validate: every claimed entry decodes to a * pushbuffer VA in the ring's window. */ for (k = 0; k < hp && k < 64; k++) { |
