summaryrefslogtreecommitdiffstats
path: root/kernel/gsp_sema_service.c
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-12 01:29:13 -0500
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-11-12 01:29:13 -0500
commitfa985e759707ce011bd238bbbb73bc422fccb90f (patch)
tree70c2b7956e3e5efaf001a02da173fc6df75ddfd6 /kernel/gsp_sema_service.c
parentfc01d736909bfaa411643eddbe1593a78c83371a (diff)
downloadopen-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.c66
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++) {