summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/gsp_phys_booter.c21
-rwxr-xr-xtools/lg/frame_sequence.sh33
2 files changed, 54 insertions, 0 deletions
diff --git a/kernel/gsp_phys_booter.c b/kernel/gsp_phys_booter.c
index b19fa0d..217f4e4 100644
--- a/kernel/gsp_phys_booter.c
+++ b/kernel/gsp_phys_booter.c
@@ -19897,6 +19897,27 @@ gr_page_unmapped:
/* A stale release from a previous submission must not be observed. */
WRITE_ONCE(*(u32 *)sem_va, 0);
WRITE_ONCE(*(u32 *)(sem_va + 4), 0);
+ /*
+ * r441: zero the GUEST-VISIBLE release words for the first attempt
+ * too, not only for outcome retries. The r439 evidence shows a first
+ * attempt whose poll broke on a STALE value (qmd_rel=0x00000005 from
+ * the previous launch's engine write, want=6) while the engine never
+ * fetched this launch's deposit (sentinel intact, "engine fetch
+ * NONE"): the host then shipped a completion for a launch that did
+ * not run. Zeroing forces the poll to wait for THIS launch's own
+ * engine write; when the engine does not write it, the timeout ladder
+ * and the software-authored completion take over (the honest path),
+ * and the wedge classification stops being satisfiable by a stale
+ * value. The write guard re-validates the target like the retry path.
+ */
+ if (qmd_rel_hpa && qmd_rel_off < GSP_PHYS_PAGE_SIZE &&
+ gsp_sema_gr_write_guard(req->rel_va, qmd_rel_hpa,
+ "gr-rel-zero-first"))
+ WRITE_ONCE(*(u32 *)((u8 *)__va(qmd_rel_hpa) + qmd_rel_off), 0);
+ if (ch_rel_hpa && ch_rel_off < GSP_PHYS_PAGE_SIZE &&
+ gsp_sema_gr_write_guard(req->rel_va, ch_rel_hpa,
+ "gr-chrel-zero-first"))
+ WRITE_ONCE(*(u32 *)((u8 *)__va(ch_rel_hpa) + ch_rel_off), 0);
wmb();
/*
diff --git a/tools/lg/frame_sequence.sh b/tools/lg/frame_sequence.sh
new file mode 100755
index 0000000..958a34a
--- /dev/null
+++ b/tools/lg/frame_sequence.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+# SPDX-License-Identifier: BSD-3-Clause
+# frame_sequence.sh - capture an animated GPU-rendered frame sequence end to
+# end: run the guest's CUDA frame producer into the kvmfr ivshmem BAR and
+# save every published frame on the host as PPM/PNG (the proven
+# CUDA -> ivshmem -> host path; see docs/05-operations/06).
+#
+# Usage: tools/lg/frame_sequence.sh [frames] [width] [height] [fps] [outdir]
+set -u
+HERE="$(cd "$(dirname "$0")" && pwd)"
+REPO="$(cd "$HERE/../.." && pwd)"
+FRAMES="${1:-40}"
+W="${2:-800}"
+H="${3:-600}"
+FPS="${4:-10}"
+OUT="${5:-/tmp/opencode/frames-seq}"
+
+mkdir -p "$OUT"
+rm -f "$OUT"/frame-*.ppm "$OUT"/frame-*.png
+
+# Start the host reader first so no published frame is missed.
+python3 "$REPO/tools/lg/frame_reader.py" --frames "$FRAMES" --out "$OUT" \
+ --timeout 240 > "$OUT/reader.log" 2>&1 &
+READER=$!
+
+sleep 1
+"$REPO/scripts/ssh_guest.sh" \
+ "sudo /tmp/frame_producer $FRAMES $W $H $FPS" 2>&1 | grep -v "Permanently added" \
+ | tail -5
+
+wait "$READER"
+echo "reader rc=$?"
+ls -1 "$OUT"/frame-*.ppm 2>/dev/null | wc -l