summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-30 16:52:03 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-30 16:52:03 -0400
commiteef52abe22798f747d460f2b4ba4fdb0d3f0b112 (patch)
treeb066b0e59fce90233a04ec909f06c6c8eeb9506f /kernel
parentdf8a4a17be111bb25879718d4c2e31b1fb12d900 (diff)
downloadopen-iov-eef52abe22798f747d460f2b4ba4fdb0d3f0b112.tar.gz
open-iov-eef52abe22798f747d460f2b4ba4fdb0d3f0b112.zip
vgsp: zero-put-skip for GR chan userd (fixes r1025 poisoned latch; submissions regression FIXED 32501/33646), revert op-translate walk-first (oops with flowing submissions; keep fill walk), NEW sema_screen_blit param - present blit PROVEN byte-exact (src=0x130e38000 spitch=1200 w=300 h=300 -> off=0x200000 rows_done=300 rc=0; window md5 b237eb04->4b751df8); remaining: client draws must execute (GR LAUNCH FAILED timeout ch_rel=0x00000000 want=0xc0ffee02, zero src=stream) - SESSION 153 r1026-r1027
Diffstat (limited to 'kernel')
-rw-r--r--kernel/gsp_sema_service.c212
1 files changed, 187 insertions, 25 deletions
diff --git a/kernel/gsp_sema_service.c b/kernel/gsp_sema_service.c
index d8ce5ee..b80640e 100644
--- a/kernel/gsp_sema_service.c
+++ b/kernel/gsp_sema_service.c
@@ -3655,6 +3655,9 @@ static u32 svc_rdw_log;
* appeared. Each scan reports its decision, a scan that found nothing
* reportable logs a sweep summary. */
static u32 svc_userdp_log;
+/* SESSION 153-CONTINUED-44 (r1026): bounded witness for zero-put USERD
+ * candidate skips (svc_chan_userd; the screen-pattern false block). */
+static u32 svc_zero_put_skip_log;
/* r829: bounded witness for the zero-entry holds (bad ring translations). */
static u32 svc_zero_entry_log;
static u8 svc_read_last_src;
@@ -6037,31 +6040,21 @@ static int svc_op_translate(struct nv_vgpu_device *vgpu, u64 va, u64 *addr,
return 0;
}
/*
- * SESSION 153-CONT-43: below-floor VAs (the driver's ABI/MMIO
- * mapping window, e.g. the X server's screen VA 0x120400000)
- * MUST resolve through the guest's own published page tables
- * before the content-scanned map. The scan can discover false
- * identity pairs for these VA numbers (a page-table page whose
- * PTE values look like VA->PA records), and a below-floor fill
- * that resolves outside vidmem is refused by the LOWFILL guard:
- * observed live `LOWFILL-REFUSED va=0x120458c00 pa=0x120458c00
- * ap=1` repeating with the X server's screen repaint stuck ~44
- * rows in (done=52800 rc=-2) - the identity pair shadowed the
- * big-page vidmem translation the walk resolves (pa=0x200000).
- * Walk-first keeps the guests' page tables authoritative for
- * this region; everything above the floor keeps the historical
- * order (pins and the scanned map are the client-VA workhorses
- * there).
- */
- if (va < SVC_VAS_FLOOR) {
- if (!svc_walk_vaspaces(vgpu, va & ~0xfffULL, &pa, &ap)) {
- *addr = pa + (va & 0xfff);
- *aperture = (ap == SVC_APERTURE_FB) ?
- CE_APERTURE_VID : CE_APERTURE_SYS;
- svc.op_tr_src = 6;
- return 0;
- }
- }
+ * SESSION 153-CONTINUED-44 (r1027): the CONT-43 walk-first for
+ * below-floor CE operands is REVERTED. With it live, the moment the
+ * client's channels actually ran (submissions 33646 via the slot
+ * hold + zero-put-skip), the guest kernel oopsed repeatedly
+ * (`clear_page_erms` page fault from `rm_ioctl [nvidia]`, then
+ * `_mapInsertBase` general protection, Xorg exited) - i.e. the
+ * walk-first resolutions for below-floor COPY operands clobbered
+ * guest kernel memory, the r365/r369 corruption class the fill
+ * guard exists for. The DDX screen-repaint poison that CONT-43
+ * fixed is a FILL class and stays fixed by svc_fill_floor_walk in
+ * svc_fill_1d; the copy path returns to the historical order
+ * (pins -> scanned map -> walk -> discovered -> targeted scan),
+ * which is the order every pre-r1025 boot (including the working
+ * r1024) ran with.
+ */
if (!svc_map_lookup(va, &pa)) {
*addr = pa;
*aperture = CE_APERTURE_SYS;
@@ -8534,6 +8527,145 @@ module_param_cb(sema_kick_probe, &nv_vgpu_sema_kick_probe_ops, NULL, 0200);
MODULE_PARM_DESC(sema_kick_probe, "Run the kick-notify executor on a VA (dev probe; session 153 CONT.18)");
/*
+ * SESSION 153-CONTINUED-44 (r1026): host-driven present blit.
+ *
+ * The client's rendered frame provably exists in guest RAM (its readback
+ * staging) while the X server scans the emulated screen surface in vidmem
+ * (base 0x200000, pitch 5120 for the 1280x720 4-bpp screen), so the window
+ * shows only the DDX's cleared fill artifact. This is a bounded, explicit
+ * present emulation: the host names the guest-PA staging of the CLIENT'S
+ * OWN GPU-rendered frame, and the kernel blits those rows into the scanned
+ * surface - never synthesizing pixels. The host drives it with:
+ *
+ * echo <src_gpa>,<src_pitch>,<w>,<h>[,<dst_off>,<dst_pitch>] \
+ * > .../parameters/sema_screen_blit
+ *
+ * (all values 0x-hex or decimal; src_pitch and w/h in bytes/pixels, bpp=4;
+ * defaults dst_off=0x200000, dst_pitch=5120). Bounded: w,h <= 4096,
+ * pitch <= 65536, total <= 64 MiB, one row buffer. Runs on a workqueue
+ * (vfio_dma_rw for the guest read, bars[1] shadow for the vidmem write),
+ * logs one line with the byte/row counts.
+ */
+#define SVC_SCREEN_BLIT_DEF_OFF 0x200000ULL
+#define SVC_SCREEN_BLIT_DEF_PITCH 5120u
+static u64 svc_screen_blit_gpa;
+static u32 svc_screen_blit_spitch, svc_screen_blit_w, svc_screen_blit_h;
+static u64 svc_screen_blit_doff;
+static u32 svc_screen_blit_dpitch;
+static void svc_screen_blit_work_fn(struct work_struct *w);
+static DECLARE_WORK(svc_screen_blit_work, svc_screen_blit_work_fn);
+
+static void svc_screen_blit_work_fn(struct work_struct *w)
+{
+ struct nv_vgpu_device *vgpu = NULL;
+ unsigned long flags;
+ u8 *row, *base;
+ size_t size;
+ u32 y, w4 = svc_screen_blit_w * 4;
+ u64 bytes = 0;
+ int i, rc = 0;
+
+ spin_lock_irqsave(&svc.chan_lock, flags);
+ for (i = 0; i < SVC_MAX_CHANNELS; i++) {
+ if (svc.chan[i].valid && svc.chan[i].vgpu) {
+ vgpu = svc.chan[i].vgpu;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&svc.chan_lock, flags);
+ if (!vgpu) {
+ pr_info("sema-screen-blit: no vgpu (no channel registered yet)\n");
+ return;
+ }
+ base = vgpu->bars[1].vaddr;
+ size = svc_fb_shadow_size(vgpu);
+ if (!base || svc_screen_blit_doff + (u64)svc_screen_blit_dpitch *
+ svc_screen_blit_h > size) {
+ pr_info("sema-screen-blit: bounds (off=0x%llx pitch=%u h=%u size=%zu)\n",
+ svc_screen_blit_doff, svc_screen_blit_dpitch,
+ svc_screen_blit_h, size);
+ return;
+ }
+ row = kmalloc(svc_screen_blit_spitch, GFP_KERNEL);
+ if (!row) {
+ pr_info("sema-screen-blit: no memory for row (pitch=%u)\n",
+ svc_screen_blit_spitch);
+ return;
+ }
+ for (y = 0; y < svc_screen_blit_h; y++) {
+ rc = svc_read(vgpu, svc_screen_blit_gpa + (u64)y *
+ svc_screen_blit_spitch, row,
+ svc_screen_blit_spitch);
+ if (rc)
+ break;
+ memcpy(base + svc_screen_blit_doff + (u64)y *
+ svc_screen_blit_dpitch, row, w4);
+ bytes += w4;
+ }
+ kfree(row);
+ pr_info("sema-screen-blit: src=0x%llx spitch=%u w=%u h=%u -> off=0x%llx dpitch=%u rows_done=%u bytes=%llu rc=%d\n",
+ svc_screen_blit_gpa, svc_screen_blit_spitch,
+ svc_screen_blit_w, svc_screen_blit_h,
+ svc_screen_blit_doff, svc_screen_blit_dpitch, y, bytes, rc);
+}
+
+static int nv_vgpu_sema_screen_blit_set(const char *val,
+ const struct kernel_param *kp)
+{
+ char buf[128];
+ int nf = 0;
+ u64 v[6] = {0};
+
+ if (!val || strlen(val) >= sizeof(buf))
+ return -EINVAL;
+ strscpy(buf, val, sizeof(buf));
+ {
+ char *p = buf;
+
+ while (nf < 6 && p && *p) {
+ char *c = strchr(p, ',');
+
+ if (c)
+ *c++ = '\0';
+ if (kstrtoull(p, 0, &v[nf]))
+ return -EINVAL;
+ nf++;
+ p = c;
+ }
+ }
+ if (nf < 4)
+ return -EINVAL;
+ svc_screen_blit_gpa = v[0];
+ svc_screen_blit_spitch = (u32)v[1];
+ svc_screen_blit_w = (u32)v[2];
+ svc_screen_blit_h = (u32)v[3];
+ svc_screen_blit_doff = nf > 4 ? v[4] : SVC_SCREEN_BLIT_DEF_OFF;
+ svc_screen_blit_dpitch = nf > 5 ? (u32)v[5] :
+ SVC_SCREEN_BLIT_DEF_PITCH;
+ if (!svc_screen_blit_gpa || !svc_screen_blit_w ||
+ !svc_screen_blit_h)
+ return -EINVAL;
+ if (svc_screen_blit_w > 4096 || svc_screen_blit_h > 4096 ||
+ svc_screen_blit_spitch > 0x10000 ||
+ svc_screen_blit_spitch < svc_screen_blit_w * 4 ||
+ svc_screen_blit_dpitch > 0x10000 ||
+ svc_screen_blit_dpitch < svc_screen_blit_w * 4 ||
+ (u64)svc_screen_blit_spitch * svc_screen_blit_h > (64u << 20))
+ return -EINVAL;
+ schedule_work(&svc_screen_blit_work);
+ return 0;
+}
+
+static const struct kernel_param_ops nv_vgpu_sema_screen_blit_ops = {
+ .set = nv_vgpu_sema_screen_blit_set,
+};
+
+module_param_cb(sema_screen_blit, &nv_vgpu_sema_screen_blit_ops, NULL, 0200);
+MODULE_PARM_DESC(sema_screen_blit,
+ "Blit a guest-RAM frame into the scanned vidmem surface: src_gpa,src_pitch,w,h[,dst_off,dst_pitch] (session 153 CONT.44, dev present emulation)");
+
+
+/*
* Close the open section: synthesize the QMD from the collected fields and
* capture it as the forwarding candidate. The QMD word layout mirrors
* svc_gr_qmd_decode() (the CUDA bridge contract): 48/49 program, 32/33
@@ -18958,6 +19090,36 @@ static int svc_chan_userd(struct nv_vgpu_device *vgpu, struct svc_channel *ch,
continue;
if (!svc_userd_probe_ex(vgpu, cand[i], as[i],
ch->gpfifo_entries, put, get, loose)) {
+ /*
+ * SESSION 153-CONTINUED-44 (r1026): a GR kernel
+ * channel's candidate read of (put == 0, arbitrary
+ * get) is not a block the client publishes to. The
+ * cleared-screen fill pattern (alternating
+ * 0xff000000 / 0x00000000 pixels) yields exactly
+ * (put=0, get=0xff000000) at every 8-byte aligned
+ * offset, and the loose large-ring acceptance
+ * (g > p allowed) latched it: r1025's every
+ * beef0100 cycle adopted fb 0x20fc00 with put=0
+ * forever (`submissions=0`, client recycles at
+ * 12 s) while the pre-walk-first boot's FB shape
+ * scan adopted the block carrying the client's
+ * real puts (`put=3/14/6`, submissions 29->208).
+ * Skip zero-put candidates for GR channels: the
+ * resolution re-runs every pass, and the FB/RAM
+ * shape scans (which require put >= 1) then adopt
+ * the block the client actually publishes on its
+ * first push. CE channels keep their layout rules
+ * (idle 0/0 acceptance is a documented CE case).
+ */
+ if (!ch->engine_type && !*put) {
+ if (svc_zero_put_skip_log < 32) {
+ svc_zero_put_skip_log++;
+ pr_info("sema-chan: userd candidate 0x%llx/%u skipped for h=0x%x (put=0 get=%u; not a published block)\n",
+ cand[i], as[i],
+ ch->h_object, *get);
+ }
+ continue;
+ }
/* ISSUE-0002 r46: name a fallback latch (CE wrong block). */
if (gsp_sema_dbg && ch->engine_type &&
ch->ce_index < 32 &&