From 8f9bb5f3f96b3dc6e98e0348c8e1e911f375a3f4 Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 19:05:04 +0000 Subject: [PATCH 01/13] =?UTF-8?q?vms-f49:=20rung=204=20=E2=80=94=20un-fake?= =?UTF-8?q?able=20ODS-2=20independent-reader=20proof=20+=20vms-1fc=20LLP64?= =?UTF-8?q?=20width=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Lands the MILESTONE of the vms-b4f ladder: prove the alpha-dec-vms GCC-port image's CRTL fopen genuinely writes to a real Files-11 ODS-2 volume over the executive ACP, not musl-ramfs — the anti-fabrication payoff (INV-6). Two coupled items in one PR, because the width fix is VALIDATED by the proof. PART A — vms-1fc (LLP64 syscall width fix). On the alpha-dec-vms C model `long`/`unsigned long` are 32 bits while pointers are 64 (LLP64), so the libvmssys raw-syscall path truncated every pointer argument to the /dev/vms transport — the ioctl(/dev/vms, ...) RMS-over-ACP write landed on a garbage address and reached nothing. - vms_syscall.h: widen __vms_syscall0..6 params + return to a guaranteed- 64-bit `vms_reg_t` (== long long), and the vms_sys_* pointer casts with it; widen vms_sys_ioctl's `arg` param from `unsigned long` to vms_reg_t. - arch/alpha/syscall_vms.c: match the widened prototypes (long long). - kif_transport_linux.c: cast the request-block pointer through vms_reg_t, not `unsigned long` — THIS is the /dev/vms pointer the proof exercises. - vms_bgsock.c: widen its ioctl pointer casts to match. No-op on the LP64 targets (x86_64/aarch64/alpha-linux-gnu: long long == long, byte-identical codegen); the actual fix only on alpha-dec-vms. VAX is untouched by construction — it takes the __NetBSD__ branch (arch/vax/vms_syscall_netbsd.h) and compiles none of these declarations. PART B — vms-f49 (rung 4, the un-fakeable gate). New `crtl-rms-veneer-gate` mode of run-module-gp-activation-alpha.sh boots the veneer-wired crtl_rms port image (JOINT_CRTL_RMS_VENEER=1) on the real /dev/vms + qemu-system-alpha; its decc$fopen -> the crtl_rms_stdio veneer -> sys$create/$put -> LIBVMSRMS$SHR -> ioctl(/dev/vms) -> ACP writes PORTTEST.DAT. Then an INDEPENDENT reader — DCL DIRECTORY/FULL, a DIFFERENT accessor than the writer's CRTL/RMS handle, running its own sys$search over the ACP directory — asserts PORTTEST.DAT;1 exists on the ODS-2 volume with a genuine ODS-2 File ID that a ramfs write cannot produce. - SYSTARTUP_VMS_VENEER_PROOF.COM: RUN JOINT_E2E, then DIRECTORY/FULL PORTTEST.DAT. - build-alpha-bootimage.sh: stage LIBVMSRMS$SHR.EXE into SYS$SHARE and swap in the veneer-proof SYSTARTUP when a veneer build is present (keyed on the shareable), verify it on the mastered volume. - assert_veneer(): gates on the independent File-ID reader, NOT console/CRTL state; a can-fail selftest proves teeth incl. the NEGATIVE/REJECTION case — a same-CRTL success that ramfs satisfies (%DIRECT-W-NOFILES) must FAIL. - ci.yml: new PR job alpha-crtl-rms-veneer (alpha_activation scope, 150m). The non-veneer alpha-crtl-rms-n7 gate stays green as the control. Local build+link verified: the veneer graph links zero-deferred under the alpha-dec-vms cc1 with the width fix (decc$fopen->DECC$SHR, veneer sys$create/$put/$get->LIBVMSRMS$SHR), LIBVMSRMS$SHR.EXE emitted; assert_veneer selftest passes all six fixtures. The qemu-alpha runtime proof runs in CI. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- .github/workflows/ci.yml | 60 +++++ .../SYSTARTUP_VMS_VENEER_PROOF.COM | 46 ++++ tools/cross-alpha/build-alpha-bootimage.sh | 29 ++- .../run-module-gp-activation-alpha.sh | 229 +++++++++++++++++- 4 files changed, 354 insertions(+), 10 deletions(-) create mode 100644 tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b117431e..f06e997e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7250,6 +7250,66 @@ jobs: - name: "crtl_rms N=7 gate — qemu-system-alpha boots the assembled OVMX/Alpha runtime, activates the crtl_rms port image (heap malloc->mallocng + RMS + stdio) on the real /dev/vms executive over the ODS-2 ACP, asserts the heap+RMS+stdio port-test OK + $STATUS=%X0035A039 (sentinel 7); runs its own can-fail selftest before the boot" run: tools/cross-alpha/run-module-gp-activation-alpha.sh crtl-rms-gate + # ----------------------------------------------------------------------- + # alpha-crtl-rms-veneer (vms-f49, rung 4 of vms-b4f): the UN-FAKEABLE CRTL->RMS + # veneer proof + the runtime validation of the vms-1fc LLP64 width fix. Same + # crtl_rms heap+RMS+stdio image as alpha-crtl-rms-n7, but built with the + # CRTL->RMS stdio veneer wired in (JOINT_CRTL_RMS_VENEER=1): its decc$fopen + # binds to sys$create over the Files-11 ACP (-> LIBVMSRMS$SHR -> ioctl(/dev/vms)) + # instead of musl-POSIX. The proof is NOT the port image's own console/CRTL + # read-back (a ramfs satisfies that identically) but an INDEPENDENT reader -- + # DCL DIRECTORY/FULL, a different accessor over the ACP -- asserting + # PORTTEST.DAT;1 exists on the real ODS-2 volume with a genuine ODS-2 File ID. + # A truncated ioctl pointer (the vms-1fc bug) would make the veneer write reach + # nothing and the independent reader draw %DIRECT-W-NOFILES -> red. alpha-crtl- + # rms-n7 stays green as the non-veneer control. Same alpha_activation scope-gate + # + budget (it reuses the identical toolchain images + build+boot machinery). + # ----------------------------------------------------------------------- + alpha-crtl-rms-veneer: + name: "OVMX/Alpha CRTL->RMS veneer gate — boots the veneer-wired crtl_rms image on the real /dev/vms executive, then an INDEPENDENT ACP reader (DIRECTORY/FULL) asserts PORTTEST.DAT;1 landed on the ODS-2 volume with a genuine File ID; validates the vms-1fc LLP64 width fix at runtime (vms-f49)" + needs: changes + if: ${{ github.event_name == 'pull_request' && needs.changes.outputs.alpha_activation == 'true' }} + runs-on: ubuntu-latest + timeout-minutes: 150 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Free up disk space + run: | + sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \ + /opt/hostedtoolcache/CodeQL /usr/local/share/boost || true + df -h / + + - name: Build the alpha-linux-gnu cross toolchain image (gha layer cache) + uses: docker/build-push-action@v6 + with: + context: tools/cross-alpha + file: tools/cross-alpha/Dockerfile + push: false + load: true + tags: ovmx-cross-alpha:latest + cache-from: type=gha,scope=cross-alpha + cache-to: type=gha,mode=max,scope=cross-alpha + + - name: Build the alpha-dec-vms cross toolchain image (gha layer cache) + uses: docker/build-push-action@v6 + with: + context: tools/cross-alpha-vms + file: tools/cross-alpha-vms/Dockerfile + push: false + load: true + tags: ovmx-cross-alpha-vms:latest + cache-from: type=gha,scope=cross-alpha-vms + cache-to: type=gha,mode=max,scope=cross-alpha-vms + + - name: "CRTL->RMS veneer gate — qemu-system-alpha boots the veneer-wired crtl_rms image on the real /dev/vms executive; its decc$fopen writes PORTTEST.DAT via sys$create over the ODS-2 ACP, then an INDEPENDENT reader (DCL DIRECTORY/FULL, a different accessor than the writer's CRTL/RMS handle) asserts PORTTEST.DAT;1 with a genuine ODS-2 File ID a ramfs cannot produce; runs a can-fail selftest (incl. the ramfs-rejection case) before the boot" + run: tools/cross-alpha/run-module-gp-activation-alpha.sh crtl-rms-veneer-gate + # ----------------------------------------------------------------------- # alpha-mf-multifile (vms-bdd): the MULTI-.O STRICT-link + activation gate -- # the rung above alpha-crtl-rms-n7 (which is single-object). The milestone diff --git a/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM b/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM new file mode 100644 index 00000000..5499c7a6 --- /dev/null +++ b/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM @@ -0,0 +1,46 @@ +$! SYSTARTUP_VMS.COM - CRTL->RMS VENEER un-fakeable proof variant +$! (vms-f49, rung 4 of the vms-b4f ladder; harness-only). +$! +$! Harness variant of the Alpha static-bootstrap SYS$MANAGER:SYSTARTUP_VMS.COM, +$! staged onto the ODS-2 volume by tools/cross-alpha/build-alpha-bootimage.sh +$! ONLY when the VENEER proof artifacts are present (LIBVMSRMS$SHR.EXE alongside +$! the joint image); the product rootfs-alpha file is never modified. +$! +$! WHAT THIS PROVES (the anti-fabrication payoff, INV-6). SYS$SYSTEM:JOINT_E2E is +$! the alpha-dec-vms GCC-port image built with the CRTL->RMS stdio veneer wired +$! in (JOINT_CRTL_RMS_VENEER=1): its decc$fopen/fwrite/fclose bind to the +$! crtl_rms_stdio.c veneer (ovmx_crtl_* -> sys$create/$put/$close -> +$! LIBVMSRMS$SHR -> ioctl(/dev/vms) -> the Files-11 ACP), NOT to musl-POSIX. It +$! writes PORTTEST.DAT through that path on the live OVMX/Alpha executive. +$! +$! Then -- and THIS is the un-fakeable part -- an INDEPENDENT reader inspects the +$! volume through a DIFFERENT accessor than the writing process's CRTL/RMS +$! handle: DCL DIRECTORY/FULL, which runs its OWN sys$parse+sys$search over the +$! Files-11 ACP directory (dcl_cmd_file.c cmd_directory -> from_acp) and prints +$! the GENUINE ODS-2 File ID (num,seq,rvn) the directory search returned. A +$! POSIX/ramfs write cannot appear in the ACP directory at all: it draws +$! %DIRECT-W-NOFILES with NO File ID line. So "PORTTEST.DAT;1 ... File ID: (n,..)" +$! here is proof the veneer's fopen genuinely landed the file on the real ODS-2 +$! volume -- something a same-CRTL fwrite->fread round-trip (which a ramfs +$! satisfies identically) can never establish. +$! +$! The bare filespec PORTTEST.DAT is deliberate: the port image RUN executes in +$! THIS STDRV process context, so its write and the DIRECTORY below resolve +$! against the identical process default -- whatever that default is, writer and +$! independent reader agree on it. If the LLP64 width fix (vms-1fc) were wrong, +$! the veneer's ioctl(/dev/vms) pointer would truncate, the write would reach +$! nothing, and DIRECTORY would report %DIRECT-W-NOFILES -- the gate reds. That +$! is the whole point: Part A (width) is VALIDATED by Part B (this reader). +$! +$ SET NOON +$! +$ WRITE SYS$OUTPUT "VENEER-PROOF: === MILESTONE: RUN JOINT_E2E (veneer crtl_rms writes PORTTEST.DAT via sys$create) ===" +$ RUN SYS$SYSTEM:JOINT_E2E +$ WRITE SYS$OUTPUT "VENEER-PROOF: WRITE-STATUS=''$STATUS' SEVERITY=''$SEVERITY'" +$! +$ WRITE SYS$OUTPUT "VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL PORTTEST.DAT (a DIFFERENT accessor over the ACP) ===" +$ DIRECTORY/FULL PORTTEST.DAT +$ WRITE SYS$OUTPUT "VENEER-PROOF: DIR-STATUS=''$STATUS' SEVERITY=''$SEVERITY'" +$ WRITE SYS$OUTPUT "VENEER-PROOF: === END INDEPENDENT READER ===" +$! +$ EXIT diff --git a/tools/cross-alpha/build-alpha-bootimage.sh b/tools/cross-alpha/build-alpha-bootimage.sh index 6cc33ace..0bf84b09 100755 --- a/tools/cross-alpha/build-alpha-bootimage.sh +++ b/tools/cross-alpha/build-alpha-bootimage.sh @@ -176,9 +176,24 @@ docker run --rm --memory=8g --cpus="$(nproc)" \ # Control image (main returns 0) -- proves the DCL-RUN fork-path status # mapping (0 -> success-class; sentinel 3 -> ABORT-with-3). Optional. [ -f "$JOINT/joint_e2e_ok.exe" ] && cp "$JOINT/joint_e2e_ok.exe" "$SYSEXE/JOINT_E2E_OK.EXE" || true - cp /repo/tools/cross-alpha/SYSTARTUP_VMS_JOINT_PROOF.COM \ - "$ST/vms/SYS0/SYSCOMMON/SYSMGR/SYSTARTUP_VMS.COM" - echo " JOINT-E2E: joint_e2e.exe -> SYS\$SYSEXE:JOINT_E2E.EXE; DECC\$SHR.EXE + LIBOTS_SHR.EXE -> SYS\$SHARE; proof SYSTARTUP staged" + # vms-f49 (rung 4): the CRTL->RMS VENEER path (JOINT_CRTL_RMS_VENEER=1) + # additionally emits LIBVMSRMS$SHR.EXE -- the port image's decc$fopen + # binds to the veneer whose sys$create/$put imports need this producer in + # SYS$SHARE at activation. Its PRESENCE in /work/joint is the signal that + # this is a veneer build, so we ALSO stage the un-fakeable independent- + # reader SYSTARTUP (DIRECTORY/FULL over the ACP) instead of the plain + # joint-proof COM. A non-veneer build leaves it absent -> byte-identical + # to before. + if [ -f "$JOINT/LIBVMSRMS\$SHR.EXE" ]; then + cp "$JOINT/LIBVMSRMS\$SHR.EXE" "$ST/vms/SYS0/SYSCOMMON/SYSLIB/LIBVMSRMS\$SHR.EXE" + cp /repo/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM \ + "$ST/vms/SYS0/SYSCOMMON/SYSMGR/SYSTARTUP_VMS.COM" + echo " JOINT-E2E (VENEER): joint_e2e.exe -> SYS\$SYSEXE; DECC\$SHR + LIBOTS_SHR + LIBVMSRMS\$SHR -> SYS\$SHARE; VENEER-proof SYSTARTUP (independent DIRECTORY/FULL reader) staged" + else + cp /repo/tools/cross-alpha/SYSTARTUP_VMS_JOINT_PROOF.COM \ + "$ST/vms/SYS0/SYSCOMMON/SYSMGR/SYSTARTUP_VMS.COM" + echo " JOINT-E2E: joint_e2e.exe -> SYS\$SYSEXE:JOINT_E2E.EXE; DECC\$SHR.EXE + LIBOTS_SHR.EXE -> SYS\$SHARE; proof SYSTARTUP staged" + fi else echo "-- (no /work/joint artifacts -- JOINT-E2E proof NOT staged) --" fi @@ -223,7 +238,13 @@ docker run --rm --memory=8g --cpus="$(nproc)" \ # shareables MUST be on the mastered ODS-2 volume (IMGACT reads them over the # ACP -- an initramfs copy is invisible to the ACP, the rc=44 gap). if [ -f "$SYSEXE/JOINT_E2E.EXE" ]; then - for jn in JOINT_E2E.EXE DECC\$SHR.EXE LIBOTS_SHR.EXE; do + JOINT_VERIFY="JOINT_E2E.EXE DECC\$SHR.EXE LIBOTS_SHR.EXE" + # vms-f49: on the veneer build, LIBVMSRMS$SHR.EXE MUST also be on the + # mastered volume -- the port image's veneer sys$create/$put imports are + # deferred against it, so an activation without it on SYS$SHARE would fail + # over the ACP (the same class as the vms-157 rc=44 initramfs-invisible gap). + [ -f "$ST/vms/SYS0/SYSCOMMON/SYSLIB/LIBVMSRMS\$SHR.EXE" ] && JOINT_VERIFY="$JOINT_VERIFY LIBVMSRMS\$SHR.EXE" + for jn in $JOINT_VERIFY; do grep -qi "$jn" /work/distrib-list.txt \ || { echo "FAIL: mastered ODS-2 image missing JOINT-E2E proof file $jn"; exit 1; } echo " OK: ovmx-distrib-alpha.img (ODS-2) carries JOINT-E2E $jn" diff --git a/tools/cross-alpha/run-module-gp-activation-alpha.sh b/tools/cross-alpha/run-module-gp-activation-alpha.sh index 8dbaf302..42f21e03 100755 --- a/tools/cross-alpha/run-module-gp-activation-alpha.sh +++ b/tools/cross-alpha/run-module-gp-activation-alpha.sh @@ -63,7 +63,8 @@ # USAGE: # tools/cross-alpha/run-module-gp-activation-alpha.sh # gate (default) # tools/cross-alpha/run-module-gp-activation-alpha.sh gate # same, explicit -# tools/cross-alpha/run-module-gp-activation-alpha.sh crtl-rms-gate # crtl_rms heap+RMS+stdio -> N=7 +# tools/cross-alpha/run-module-gp-activation-alpha.sh crtl-rms-gate # crtl_rms heap+RMS+stdio -> N=7 (non-veneer control) +# tools/cross-alpha/run-module-gp-activation-alpha.sh crtl-rms-veneer-gate # vms-f49 rung 4: veneer write + INDEPENDENT ODS-2 File-ID reader # tools/cross-alpha/run-module-gp-activation-alpha.sh mf-gate # multi-.o cross-boundary -> N=5 (vms-bdd) # tools/cross-alpha/run-module-gp-activation-alpha.sh selftest # can-fail proof, no boot # @@ -110,6 +111,12 @@ MILESTONE_MAIN=joint_main.c # main. Empty for the N=3 / N=7 single-object gates; the `mf-gate' mode sets it to # mf_util.c so the multi-.o cross-boundary program (mf_main.c) is built + activated. MILESTONE_EXTRA="" +# JOINT_CRTL_RMS_VENEER (vms-f49, rung 4 of vms-b4f): default 0, so the gate/ +# crtl-rms-gate/mf-gate modes build byte-identically to before. The +# `crtl-rms-veneer-gate' mode sets it to 1 so build-joint-image.sh composes the +# two-pass CRTL->RMS stdio veneer + emits LIBVMSRMS$SHR.EXE, and the port image's +# decc$fopen binds to sys$create over the ACP instead of musl-POSIX. +JOINT_CRTL_RMS_VENEER=0 log() { echo "[modgp-activation] $*"; } die() { echo "[modgp-activation] FATAL: $*" >&2; exit 1; } @@ -256,6 +263,76 @@ assert_mf() { return 1 } +# assert_veneer -- THE TEETH for the vms-f49 rung-4 un-fakeable +# CRTL->RMS veneer proof (`crtl-rms-veneer-gate' mode). This is the anti- +# fabrication payoff (INV-6): it does NOT trust the port image's own console +# text or its same-process CRTL/RMS read-back (which a ramfs satisfies +# IDENTICALLY -- that is exactly what the plain crtl-rms N=7 gate can be fooled +# by). It gates on an INDEPENDENT reader -- DCL DIRECTORY/FULL, a DIFFERENT +# accessor that runs its OWN sys$parse+sys$search over the Files-11 ACP directory +# (dcl_cmd_file.c cmd_directory, from_acp) and prints the GENUINE ODS-2 File ID +# (num,seq,rvn) the on-disk directory returned. A POSIX/ramfs write cannot appear +# in the ACP directory at all (it draws %DIRECT-W-NOFILES, NO File ID line), so a +# PORTTEST.DAT;1 File-ID line here is proof the veneer's fopen genuinely landed +# the file on the real ODS-2 volume. Pass iff: +# (a) the veneer write completed -- crtl_rms port-test OK + executive N=7 seam; +# (b) THE TEETH: the INDEPENDENT DIRECTORY/FULL reader region shows +# PORTTEST.DAT;1 with a NONZERO ODS-2 File ID and NO %DIRECT-W-NOFILES; +# (c) no activation-failure %-error. +# Pure function over the console transcript; shared verbatim by the real BOOT-A +# run and the can-fail selftest. +assert_veneer() { + local log="$1" + [ -f "$log" ] || { echo " FAIL: no console log at $log"; return 1; } + + # (a) the veneer write ran: crtl_rms heap+RMS+stdio OK line + N=7 seam. With + # the veneer, fopen/fwrite/fclose route sys$create/$put over the ACP; a broken + # LLP64 width (vms-1fc) would truncate the ioctl pointer, fwrite would short, + # and the image would return <7 with no OK line -- so this already needs the + # write path to work end to end. + local port_ok seam mile_hex mile_dec sentinel="?" mile_ok=0 + port_ok=$(grep -qaE "OVMX CRTL/RMS port test: OK \(heap\+RMS\+stdio\)" "$log" && echo 1 || echo 0) + seam=$(grep -aoE "OVMX-SEAM: image=JOINT_E2E\.EXE[^\"]*STATUS=0x[0-9A-Fa-f]+" "$log" 2>/dev/null | tail -1) + mile_hex=$(printf '%s' "$seam" | grep -oiE '0x[0-9a-f]+' | tail -1) + if [ -n "$mile_hex" ]; then + mile_dec=$(( mile_hex )) + if [ "$mile_dec" -ge "$CEXIT1" ] && [ $(( (mile_dec - CEXIT1) % 8 )) -eq 0 ]; then + sentinel=$(( (mile_dec - CEXIT1) / 8 + 1 )) + [ "$sentinel" -eq 7 ] && mile_ok=1 + fi + fi + + # (b) THE TEETH -- confine the check to the INDEPENDENT-reader region so no + # stray earlier token can satisfy it. DIRECTORY/FULL prints the name+version + # and the genuine File ID on one line ("PORTTEST.DAT;1 File ID: (14,1,0)"), + # ONLY when the entry came from the ACP search (from_acp); a ramfs/POSIX write + # never reaches the ACP directory and draws %DIRECT-W-NOFILES instead. + local region fid_line fid_num=0 reader_ok=0 nofiles=0 + region=$(awk '/VENEER-PROOF: === INDEPENDENT READER/{f=1} f{print} /VENEER-PROOF: DIR-STATUS/{f=0}' "$log") + printf '%s' "$region" | grep -qaE "%DIRECT-W-NOFILES" && nofiles=1 + fid_line=$(printf '%s' "$region" | grep -aoE "PORTTEST\.DAT;1[^A-Za-z]*File ID:[[:space:]]*\([0-9]+,[0-9]+,[0-9]+\)" | tail -1) + if [ -n "$fid_line" ]; then + fid_num=$(printf '%s' "$fid_line" | grep -oE '\([0-9]+' | tr -d '(' | tail -1) + [ -n "$fid_num" ] && [ "$fid_num" -gt 0 ] && [ "$nofiles" -eq 0 ] && reader_ok=1 + fi + + # (c) no activation-failure %-error (a crash before/at main, or an IMGACT-side + # error). DIRECTORY's own %DIRECT-W-NOFILES is handled in (b), NOT here. + local errs err_ok=1 + errs=$(grep -aE "%IMGACT-F|IMGNOTFND|DEVNOTMOUNT|NOSUCHFILE|ACCVIO|terminated abnormally|signal 1[012]|signal [46]|%X0000002C" "$log" 2>/dev/null || true) + [ -n "$errs" ] && err_ok=0 + + echo " (a) veneer write (crtl_rms OK + N=7 seam) : port_ok=$port_ok seam=${seam:-}" + echo " decode: (${mile_hex:-} - C\$_EXIT1 0x35a009)/8 + 1 = $sentinel (want 7; ok=$mile_ok)" + echo " (b) INDEPENDENT ACP reader (DIRECTORY/FULL): ${fid_line:-}" + echo " nofiles=$nofiles fid=$fid_num (want a nonzero ODS-2 File ID, ramfs cannot produce this; reader_ok=$reader_ok)" + echo " (c) no activation err : ok=$err_ok" + [ "$err_ok" -eq 0 ] && echo " offending: $(printf '%s' "$errs" | tr '\n' '|')" + + [ "$port_ok" -eq 1 ] && [ "$mile_ok" -eq 1 ] && [ "$reader_ok" -eq 1 ] && [ "$err_ok" -eq 1 ] && return 0 + return 1 +} + # --------------------------------------------------------------------------- # build_joint_images -- build the N=3 milestone image (joint_main.c -> return 3) # and the SS$_NORMAL control (joint_main_ok.c -> return 0) with the SAME merged @@ -274,14 +351,20 @@ build_joint_images() { # rung (`mf-gate' sets MILESTONE_MAIN=mf_main.c MILESTONE_EXTRA=mf_util.c so # mf_main.obj calls across the boundary into mf_util.obj). Empty for the N=3 and # N=7 gates, so they build byte-identically. - log "step 1a: build the milestone image ($MILESTONE_MAIN${MILESTONE_EXTRA:+ + $MILESTONE_EXTRA}, sentinel $WANT_SENTINEL) with the merged toolchain" - JOINT_MAIN="$MILESTONE_MAIN" JOINT_EXTRA="${MILESTONE_EXTRA:-}" IMG="$VMS_IMG" bash "$bji" "$out_n3" \ + # vms-f49: both the milestone AND the control build with the SAME veneer flag so + # both link against the identical staged DECC$SHR (+ LIBVMSRMS$SHR) symbol vector + # -- a veneer milestone with a non-veneer control would stage one DECC$SHR but + # link the other image against a different one. Default 0 keeps every other mode + # byte-identical. + log "step 1a: build the milestone image ($MILESTONE_MAIN${MILESTONE_EXTRA:+ + $MILESTONE_EXTRA}, sentinel $WANT_SENTINEL${JOINT_CRTL_RMS_VENEER:+ veneer=$JOINT_CRTL_RMS_VENEER}) with the merged toolchain" + JOINT_MAIN="$MILESTONE_MAIN" JOINT_EXTRA="${MILESTONE_EXTRA:-}" \ + JOINT_CRTL_RMS_VENEER="$JOINT_CRTL_RMS_VENEER" IMG="$VMS_IMG" bash "$bji" "$out_n3" \ || die "build-joint-image.sh (milestone $MILESTONE_MAIN) failed -- see $out_n3/build.log" grep -q 'LINK-S-CREATED' "$out_n3/build.log" \ || die "milestone image did not link (no %LINK-S-CREATED) -- see $out_n3/build.log" log "step 1b: build the SS\$_NORMAL control image (joint_main_ok.c, return 0) with the merged toolchain" - JOINT_MAIN=joint_main_ok.c IMG="$VMS_IMG" bash "$bji" "$out_ok" \ + JOINT_MAIN=joint_main_ok.c JOINT_CRTL_RMS_VENEER="$JOINT_CRTL_RMS_VENEER" IMG="$VMS_IMG" bash "$bji" "$out_ok" \ || die "build-joint-image.sh (control) failed -- see $out_ok/build.log" grep -q 'LINK-S-CREATED' "$out_ok/build.log" \ || die "control image did not link (no %LINK-S-CREATED) -- see $out_ok/build.log" @@ -296,7 +379,18 @@ build_joint_images() { for f in "joint_e2e.exe" "joint_e2e_ok.exe" "DECC\$SHR.EXE" "LIBOTS_SHR.EXE"; do [ -s "$WORK/joint/$f" ] || die "joint artifact $WORK/joint/$f missing/empty after build" done - log "step 1: joint images staged into $WORK/joint (milestone N=3 + SS\$_NORMAL control + producers)" + # vms-f49: on a veneer build, stage LIBVMSRMS$SHR.EXE too -- build-joint-image.sh + # emits it into $out_n3 whenever JOINT_CRTL_RMS_VENEER=1. Its presence in + # $WORK/joint is exactly the signal build-alpha-bootimage.sh keys on to stage the + # producer into SYS$SHARE + swap in the VENEER-proof SYSTARTUP. + if [ "$JOINT_CRTL_RMS_VENEER" = 1 ]; then + [ -s "$out_n3/LIBVMSRMS\$SHR.EXE" ] \ + || die "veneer build produced no LIBVMSRMS\$SHR.EXE in $out_n3 (JOINT_CRTL_RMS_VENEER=1 expected it)" + cp "$out_n3/LIBVMSRMS\$SHR.EXE" "$WORK/joint/LIBVMSRMS\$SHR.EXE" + log "step 1: joint images staged into $WORK/joint (VENEER milestone N=$WANT_SENTINEL + control + DECC\$SHR/LIBOTS/LIBVMSRMS\$SHR producers)" + else + log "step 1: joint images staged into $WORK/joint (milestone N=$WANT_SENTINEL + SS\$_NORMAL control + producers)" + fi } # --------------------------------------------------------------------------- @@ -589,7 +683,130 @@ EOF grep -aE "%IMGACT|%RUN-|%DCL-|IMGNOTFND|NOSUCHFILE|DEVNOTMOUNT|ACCVIO|SS\\\$_" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -20 || echo " (none captured)" exit 1 ;; + crtl-rms-veneer-gate) + # vms-f49 (rung 4 of vms-b4f): the un-fakeable CRTL->RMS veneer proof. Same + # crtl_rms milestone image (heap+RMS+stdio, sentinel 7) as `crtl-rms-gate', + # but built with the CRTL->RMS stdio VENEER wired in (JOINT_CRTL_RMS_VENEER=1) + # so its decc$fopen/fwrite/fclose bind to sys$create/$put over the Files-11 + # ACP (-> LIBVMSRMS$SHR -> ioctl(/dev/vms)) instead of musl-POSIX. The proof + # is NOT the port image's own console/CRTL read-back (a ramfs satisfies that + # identically -- exactly what `crtl-rms-gate' cannot distinguish); it is an + # INDEPENDENT reader (DCL DIRECTORY/FULL, a different accessor over the ACP) + # asserting PORTTEST.DAT;1 exists on the ODS-2 volume with a genuine File ID. + # This is what VALIDATES the vms-1fc LLP64 width fix at runtime: a truncated + # ioctl pointer makes the veneer write reach nothing, and the independent + # reader draws %DIRECT-W-NOFILES -> the gate reds. + MILESTONE_MAIN=crtl_rms_test.c + WANT_SENTINEL=7 + JOINT_CRTL_RMS_VENEER=1 + + # Prove assert_veneer has teeth before trusting a green boot. The key case is + # the NEGATIVE/REJECTION one (2/6): a same-CRTL success (port-test OK + N=7 + # seam) that a ramfs satisfies IDENTICALLY must FAIL when the INDEPENDENT + # DIRECTORY reader shows %DIRECT-W-NOFILES -- proving the reader, not the + # console/CRTL state, is what gates. A gate that cannot fail certifies nothing. + _st=$(mktemp -d); _fails=0 + cat > "$_st/pass.log" <<'EOF' +OVMX CRTL/RMS port test: wrote+read 8192 bytes via 'PORTTEST.DAT', pattern verified +OVMX CRTL/RMS port test: OK (heap+RMS+stdio) argc=1 +OVMX-SEAM: image=JOINT_E2E.EXE stdcall_returned=1 has_exited=1 $STATUS=0x0035a039 +VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL PORTTEST.DAT (a DIFFERENT accessor over the ACP) === + +Directory DKA0:[SYSMGR] + +PORTTEST.DAT;1 File ID: (14,1,0) +Size: 16/16 Owner: [001,004] + +Total of 1 file. +VENEER-PROOF: DIR-STATUS=%X00000001 SEVERITY=1 +EOF + # NEGATIVE: same-CRTL success but the file landed on ramfs -> the independent + # ACP reader finds nothing. MUST FAIL. + cat > "$_st/ramfs.log" <<'EOF' +OVMX CRTL/RMS port test: wrote+read 8192 bytes via 'PORTTEST.DAT', pattern verified +OVMX CRTL/RMS port test: OK (heap+RMS+stdio) argc=1 +OVMX-SEAM: image=JOINT_E2E.EXE stdcall_returned=1 has_exited=1 $STATUS=0x0035a039 +VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL PORTTEST.DAT (a DIFFERENT accessor over the ACP) === +%DIRECT-W-NOFILES, no files found +VENEER-PROOF: DIR-STATUS=%X00018292 SEVERITY=0 +EOF + # NO File ID line (a from_acp=0 / passthrough-style entry with no ODS-2 File + # ID) -> MUST FAIL: the File ID is the un-fakeable token. + cat > "$_st/nofid.log" <<'EOF' +OVMX CRTL/RMS port test: OK (heap+RMS+stdio) argc=1 +OVMX-SEAM: image=JOINT_E2E.EXE stdcall_returned=1 has_exited=1 $STATUS=0x0035a039 +VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL PORTTEST.DAT (a DIFFERENT accessor over the ACP) === +PORTTEST.DAT;1 +VENEER-PROOF: DIR-STATUS=%X00000001 SEVERITY=1 +EOF + # ZERO File ID -> MUST FAIL (a genuine ODS-2 create never mints fid 0). + cat > "$_st/zerofid.log" <<'EOF' +OVMX CRTL/RMS port test: OK (heap+RMS+stdio) argc=1 +OVMX-SEAM: image=JOINT_E2E.EXE stdcall_returned=1 has_exited=1 $STATUS=0x0035a039 +VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL PORTTEST.DAT (a DIFFERENT accessor over the ACP) === +PORTTEST.DAT;1 File ID: (0,0,0) +VENEER-PROOF: DIR-STATUS=%X00000001 SEVERITY=1 +EOF + # WRONG SENTINEL (N=3, not 7) -> MUST FAIL. + cat > "$_st/wrong.log" <<'EOF' +OVMX CRTL/RMS port test: OK (heap+RMS+stdio) argc=1 +OVMX-SEAM: image=JOINT_E2E.EXE stdcall_returned=1 has_exited=1 $STATUS=0x0035a019 +VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL PORTTEST.DAT (a DIFFERENT accessor over the ACP) === +PORTTEST.DAT;1 File ID: (14,1,0) +VENEER-PROOF: DIR-STATUS=%X00000001 SEVERITY=1 +EOF + # ACTIVATION CRASH (no port line + ACCVIO) -> MUST FAIL. + cat > "$_st/crash.log" <<'EOF' +%DCL-F-ABORT, image SYS$SYSTEM:JOINT_E2E terminated abnormally (signal 11) +JOINT-E2E-PROOF: STATUS=%X0000002C SEVERITY=4 +EOF + echo "-- veneer selftest 1/6: clean veneer write + independent File-ID reader must PASS --" + if assert_veneer "$_st/pass.log" >/dev/null 2>&1; then echo " PASS"; else echo " FAIL: clean proof rejected"; _fails=$((_fails+1)); fi + echo "-- veneer selftest 2/6: same-CRTL success but ramfs (%DIRECT-W-NOFILES) must FAIL --" + if assert_veneer "$_st/ramfs.log" >/dev/null 2>&1; then echo " FAIL: ramfs round-trip accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + echo "-- veneer selftest 3/6: PORTTEST.DAT;1 with NO File ID line must FAIL --" + if assert_veneer "$_st/nofid.log" >/dev/null 2>&1; then echo " FAIL: missing File ID accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + echo "-- veneer selftest 4/6: zero File ID (0,0,0) must FAIL --" + if assert_veneer "$_st/zerofid.log" >/dev/null 2>&1; then echo " FAIL: zero File ID accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + echo "-- veneer selftest 5/6: wrong sentinel (N=3 not 7) must FAIL --" + if assert_veneer "$_st/wrong.log" >/dev/null 2>&1; then echo " FAIL: wrong sentinel accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + echo "-- veneer selftest 6/6: activation crash (no port line + ACCVIO) must FAIL --" + if assert_veneer "$_st/crash.log" >/dev/null 2>&1; then echo " FAIL: crash accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + rm -rf "$_st" + [ "$_fails" -eq 0 ] || die "veneer selftest failed -- assert_veneer cannot be trusted; aborting before the boot" + echo "" + + build_joint_images + assemble_boot_image + log "step 3: BOOT A -- activate the VENEER crtl_rms image + run the INDEPENDENT DIRECTORY reader on the REAL executive" + run_boot_a + echo "" + echo "========================================================================" + echo "== vms-f49 rung 4: CRTL->RMS veneer -> real ODS-2 landing, PROVEN by an" + echo "== INDEPENDENT ACP reader (DIRECTORY/FULL File ID) on the real OVMX/Alpha" + echo "== executive (qemu-system-alpha + /dev/vms). Validates the vms-1fc width fix." + echo "========================================================================" + grep -aE "VENEER-PROOF:|OVMX CRTL/RMS|OVMX-SEAM:|PORTTEST\.DAT|File ID:|%DIRECT|%IMGACT|%DCL-" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ | /' || true + echo "------------------------------------------------------------------------" + if assert_veneer "$WORK/modgpA.log"; then + echo "" + echo "PASS: the veneer-wired port image's decc\$fopen genuinely landed PORTTEST.DAT on" + echo " the real Files-11 ODS-2 volume over the ACP -- an INDEPENDENT reader" + echo " (DIRECTORY/FULL, a different accessor than the writer's CRTL/RMS handle)" + echo " returned a genuine ODS-2 File ID that a ramfs write cannot produce. The" + echo " vms-1fc LLP64 width fix holds at runtime: the ioctl pointer was NOT truncated." + exit 0 + fi + echo "" + echo "FAIL: the veneer write did NOT land on the real ODS-2 volume (the independent ACP" + echo " reader saw no genuine File ID). If PORTTEST.DAT;1 is absent (%DIRECT-W-NOFILES)" + echo " while the port image reported same-CRTL success, that is the vms-1fc truncated-" + echo " pointer symptom (Part A) -- the veneer ioctl(/dev/vms) landed on a bad address." + echo " Full log: $WORK/modgpA.log" + grep -aE "VENEER-PROOF:|%IMGACT|%RUN-|%DCL-|IMGNOTFND|NOSUCHFILE|DEVNOTMOUNT|ACCVIO|%DIRECT|SS\\\$_" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -25 || echo " (none captured)" + exit 1 + ;; *) - die "unknown mode '$MODE' (use: gate | crtl-rms-gate | mf-gate | selftest)" + die "unknown mode '$MODE' (use: gate | crtl-rms-gate | crtl-rms-veneer-gate | mf-gate | selftest)" ;; esac From 3af4412fe5229e4ffb75a505e2e6f362bf8f99af Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 19:29:16 +0000 Subject: [PATCH 02/13] vms-f49: fix apostrophe quote-break in build-alpha-bootimage.sh staging block The vms-f49 staging comments landed inside the assemble `docker run ... bash -c '...'` SINGLE-QUOTED block with apostrophes ("image's"), which closed the quote mid-body and exposed `decc$fopen` to the outer shell -> `line 91: fopen: unbound variable` under `set -u`. This broke the boot-image assembly for EVERY alpha activation gate that calls assemble_boot_image (gate/crtl-rms-gate/mf-gate/ crtl-rms-veneer-gate), before any qemu boot -- NOT a Part A regression (all three reds died at the identical line-91 quote-break after "step 1 staged", pre-boot; Part A links clean, proven by the green alpha RMS-substrate STRICT-link + DECC$SHR jobs). The script's own header warns "no apostrophes in this block". Reworded the two added comments apostrophe-free; verified the docker -c body now has balanced single-quotes with zero outer-shell `$` exposure. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- tools/cross-alpha/build-alpha-bootimage.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/cross-alpha/build-alpha-bootimage.sh b/tools/cross-alpha/build-alpha-bootimage.sh index 0bf84b09..c508abe3 100755 --- a/tools/cross-alpha/build-alpha-bootimage.sh +++ b/tools/cross-alpha/build-alpha-bootimage.sh @@ -177,13 +177,14 @@ docker run --rm --memory=8g --cpus="$(nproc)" \ # mapping (0 -> success-class; sentinel 3 -> ABORT-with-3). Optional. [ -f "$JOINT/joint_e2e_ok.exe" ] && cp "$JOINT/joint_e2e_ok.exe" "$SYSEXE/JOINT_E2E_OK.EXE" || true # vms-f49 (rung 4): the CRTL->RMS VENEER path (JOINT_CRTL_RMS_VENEER=1) - # additionally emits LIBVMSRMS$SHR.EXE -- the port image's decc$fopen - # binds to the veneer whose sys$create/$put imports need this producer in + # additionally emits LIBVMSRMS$SHR.EXE -- the port image decc$fopen binds + # to the veneer whose sys$create/$put imports need this producer in # SYS$SHARE at activation. Its PRESENCE in /work/joint is the signal that # this is a veneer build, so we ALSO stage the un-fakeable independent- # reader SYSTARTUP (DIRECTORY/FULL over the ACP) instead of the plain # joint-proof COM. A non-veneer build leaves it absent -> byte-identical - # to before. + # to before. (No apostrophes in this block -- it runs inside the assemble + # docker bash -c single-quote; an apostrophe would break the quote.) if [ -f "$JOINT/LIBVMSRMS\$SHR.EXE" ]; then cp "$JOINT/LIBVMSRMS\$SHR.EXE" "$ST/vms/SYS0/SYSCOMMON/SYSLIB/LIBVMSRMS\$SHR.EXE" cp /repo/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM \ @@ -240,7 +241,7 @@ docker run --rm --memory=8g --cpus="$(nproc)" \ if [ -f "$SYSEXE/JOINT_E2E.EXE" ]; then JOINT_VERIFY="JOINT_E2E.EXE DECC\$SHR.EXE LIBOTS_SHR.EXE" # vms-f49: on the veneer build, LIBVMSRMS$SHR.EXE MUST also be on the - # mastered volume -- the port image's veneer sys$create/$put imports are + # mastered volume -- the port image veneer sys$create/$put imports are # deferred against it, so an activation without it on SYS$SHARE would fail # over the ACP (the same class as the vms-157 rc=44 initramfs-invisible gap). [ -f "$ST/vms/SYS0/SYSCOMMON/SYSLIB/LIBVMSRMS\$SHR.EXE" ] && JOINT_VERIFY="$JOINT_VERIFY LIBVMSRMS\$SHR.EXE" From ac2d7218194a2aad6d111c7c1a992660be784ffe Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 19:49:29 +0000 Subject: [PATCH 03/13] vms-f49: stage the full RMS producer graph + fix its DECC producer name (rung-4 activation) The rung-4 veneer gate booted this time (N=7 control PASSED -> Part A width fix does NOT regress alpha activation) but the veneer image RUN drew %IMGACT-F-IMGNOTFND: LIBVMSRMS$SHR is not self-contained. It transitively imports from the whole executive producer graph (LIBVMS/LIBVMSFS/LIBVMSLNM/LIBVMSPROCESS/ LIBVMSSYS$SHR) AND recorded its DECC producer as the phantom pass-1 bootstrap name "DECC1$SHR.EXE" -- neither on SYS$SHARE, so IMGACT could not resolve them. Two in-scope Part-B wiring fixes (no new executive facility): - build-joint-image.sh: build the pass-1 bootstrap DECC under $WORK/p1 with the BASENAME DECC$SHR.EXE (not DECC1$SHR.EXE). LINK records producers by basename, so the graph + LIBVMSRMS$SHR now record "DECC$SHR.EXE" and, at activation, IMGACT name-keyed binding resolves them against the SINGLE staged pass-2 (veneer) DECC$SHR.EXE (GSMATCH LEQUAL). One DECC$SHR at runtime, no duplicate musl C-RTL. Also emit the whole producer graph to OUTDIR. - run-module-gp-activation-alpha.sh + build-alpha-bootimage.sh: stage the full graph (LIBVMSRMS/LIBVMS/LIBVMSFS/LIBVMSLNM/LIBVMSPROCESS/LIBVMSSYS$SHR) into SYS$SHARE and verify each on the mastered ODS-2 volume. Also fixes a second single-quote apostrophe break ("IMGACT's", and 'DECC$SHR.EXE' exposing $SHR) in the build-joint-image.sh docker bash -c block. Local verify: veneer graph links zero-deferred; LIBVMSRMS$SHR + all 7 sibling shareables now record DECC$SHR.EXE (grep DECC1 = 0 across the whole staged set); full graph emitted to OUTDIR. Runtime activation runs in CI. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- .../joint-e2e/build-joint-image.sh | 27 ++++++++++++++++--- tools/cross-alpha/build-alpha-bootimage.sh | 17 +++++++++--- .../run-module-gp-activation-alpha.sh | 15 ++++++++--- 3 files changed, 49 insertions(+), 10 deletions(-) diff --git a/tools/cross-alpha-vms/joint-e2e/build-joint-image.sh b/tools/cross-alpha-vms/joint-e2e/build-joint-image.sh index f8f8a3ab..b3db537c 100755 --- a/tools/cross-alpha-vms/joint-e2e/build-joint-image.sh +++ b/tools/cross-alpha-vms/joint-e2e/build-joint-image.sh @@ -217,11 +217,23 @@ if [ "$JOINT_CRTL_RMS_VENEER" = 1 ]; then MK=/src/src/vmslink OTS="$WORK/libots/LIBOTS_SHR.EXE" - echo "-- [vms-2655] DECC\$SHR pass 1 (bootstrap, no veneer) --" + # vms-f49 (rung 4): build the pass-1 bootstrap DECC under its OWN directory + # but with the BASENAME DECC$SHR.EXE (NOT DECC1$SHR.EXE). The producer graph + + # LIBVMSRMS$SHR --use this file, and LINK.EXE records the producer by BASENAME + # into their .vms$imp -- so with the basename DECC$SHR.EXE they record the name + # DECC$SHR.EXE and, at ACTIVATION, the IMGACT name-keyed binding resolves those + # imports against the SINGLE staged pass-2 (veneer) DECC$SHR.EXE (GSMATCH + # LEQUAL: pass 2 only appends the veneer aliases, so every pass-1 universal the + # graph bound is still present). Under the old DECC1$SHR.EXE basename the graph + # recorded a producer name that does NOT exist on SYS$SHARE -> the rung-4 + # activation failed %IMGACT-F-IMGNOTFND. One DECC$SHR at runtime, not two -- no + # duplicate musl C-RTL. (No apostrophes in this block -- docker bash -c quote.) + echo "-- [vms-2655] DECC\$SHR pass 1 (bootstrap, no veneer; basename DECC\$SHR.EXE for runtime name-binding) --" + mkdir -p "$WORK/p1" OVMX_DECC_ARCH=alpha NM="$PREFIX/bin/alpha-dec-vms-nm" AR_HOST=ar \ ALPHA_CC="$ALPHA_CC" ALPHA_MUSL_SRC="$MUSL_SRC" DECC_USE="$OTS" \ - sh "$MK/mk_decc_shr.sh" "$WORK/LINK.EXE" "$WORK/DECC1\$SHR.EXE" "$LIBC" "$LIBGCC" - DECC1="$WORK/DECC1\$SHR.EXE" + sh "$MK/mk_decc_shr.sh" "$WORK/LINK.EXE" "$WORK/p1/DECC\$SHR.EXE" "$LIBC" "$LIBGCC" + DECC1="$WORK/p1/DECC\$SHR.EXE" echo "-- [vms-2655] the OVMX producer graph (rung 1, unchanged), using DECC1 --" export ALPHA_CC ALPHA_MUSL_SRC="$MUSL_SRC" OVMX_DECC_ARCH=alpha ALPHA_OTS_USE="$OTS" @@ -240,6 +252,15 @@ if [ "$JOINT_CRTL_RMS_VENEER" = 1 ]; then sh "$MK/mk_vmsrms_shr.sh" "$WORK/LINK.EXE" "$OUT/LIBVMSRMS\$SHR.EXE" "$DECC1" "$VMS" "$FS" "$SYS" RMS="$OUT/LIBVMSRMS\$SHR.EXE" + # vms-f49 (rung 4): LIBVMSRMS$SHR is NOT self-contained -- at activation it + # (transitively) imports from the WHOLE executive producer graph + # (LIBVMS$SHR/LIBVMSFS$SHR/LIBVMSLNM$SHR/LIBVMSPROCESS$SHR/LIBVMSSYS$SHR), so + # every one of those shareables must be on SYS$SHARE for IMGACT to resolve the + # veneer image. Emit them to OUTDIR alongside LIBVMSRMS$SHR (rung 3 only staged + # LIBVMSRMS$SHR, which is why the rung-4 activation drew %IMGACT-F-IMGNOTFND on + # the first unstaged producer). A non-veneer run never enters this block. + cp "$SYS" "$PROC" "$LNM" "$FS" "$VMS" "$OUT/" + echo "-- [vms-2655] DECC\$SHR pass 2 (final, CRTL->RMS stdio veneer wired, vms-ed1e) --" OVMX_DECC_ARCH=alpha NM="$PREFIX/bin/alpha-dec-vms-nm" AR_HOST=ar \ ALPHA_CC="$ALPHA_CC" ALPHA_MUSL_SRC="$MUSL_SRC" DECC_USE="$OTS" \ diff --git a/tools/cross-alpha/build-alpha-bootimage.sh b/tools/cross-alpha/build-alpha-bootimage.sh index c508abe3..1f14ebe4 100755 --- a/tools/cross-alpha/build-alpha-bootimage.sh +++ b/tools/cross-alpha/build-alpha-bootimage.sh @@ -186,10 +186,18 @@ docker run --rm --memory=8g --cpus="$(nproc)" \ # to before. (No apostrophes in this block -- it runs inside the assemble # docker bash -c single-quote; an apostrophe would break the quote.) if [ -f "$JOINT/LIBVMSRMS\$SHR.EXE" ]; then - cp "$JOINT/LIBVMSRMS\$SHR.EXE" "$ST/vms/SYS0/SYSCOMMON/SYSLIB/LIBVMSRMS\$SHR.EXE" + # Stage the FULL executive producer graph the veneer image imports at + # activation (LIBVMSRMS$SHR is not self-contained -- it transitively + # needs LIBVMS/LIBVMSFS/LIBVMSLNM/LIBVMSPROCESS/LIBVMSSYS$SHR). Any + # producer missing from SYS$SHARE -> %IMGACT-F-IMGNOTFND at RUN. + for _vp in LIBVMSRMS LIBVMS LIBVMSFS LIBVMSLNM LIBVMSPROCESS LIBVMSSYS; do + [ -f "$JOINT/${_vp}\$SHR.EXE" ] \ + && cp "$JOINT/${_vp}\$SHR.EXE" "$ST/vms/SYS0/SYSCOMMON/SYSLIB/${_vp}\$SHR.EXE" \ + || { echo "FAIL: veneer producer $JOINT/${_vp}\$SHR.EXE missing"; exit 1; } + done cp /repo/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM \ "$ST/vms/SYS0/SYSCOMMON/SYSMGR/SYSTARTUP_VMS.COM" - echo " JOINT-E2E (VENEER): joint_e2e.exe -> SYS\$SYSEXE; DECC\$SHR + LIBOTS_SHR + LIBVMSRMS\$SHR -> SYS\$SHARE; VENEER-proof SYSTARTUP (independent DIRECTORY/FULL reader) staged" + echo " JOINT-E2E (VENEER): joint_e2e.exe -> SYS\$SYSEXE; DECC\$SHR + LIBOTS_SHR + full RMS producer graph (LIBVMSRMS/LIBVMS/LIBVMSFS/LIBVMSLNM/LIBVMSPROCESS/LIBVMSSYS\$SHR) -> SYS\$SHARE; VENEER-proof SYSTARTUP (independent DIRECTORY/FULL reader) staged" else cp /repo/tools/cross-alpha/SYSTARTUP_VMS_JOINT_PROOF.COM \ "$ST/vms/SYS0/SYSCOMMON/SYSMGR/SYSTARTUP_VMS.COM" @@ -244,7 +252,10 @@ docker run --rm --memory=8g --cpus="$(nproc)" \ # mastered volume -- the port image veneer sys$create/$put imports are # deferred against it, so an activation without it on SYS$SHARE would fail # over the ACP (the same class as the vms-157 rc=44 initramfs-invisible gap). - [ -f "$ST/vms/SYS0/SYSCOMMON/SYSLIB/LIBVMSRMS\$SHR.EXE" ] && JOINT_VERIFY="$JOINT_VERIFY LIBVMSRMS\$SHR.EXE" + # The whole transitive producer graph must be present, not just LIBVMSRMS. + for _vp in LIBVMSRMS LIBVMS LIBVMSFS LIBVMSLNM LIBVMSPROCESS LIBVMSSYS; do + [ -f "$ST/vms/SYS0/SYSCOMMON/SYSLIB/${_vp}\$SHR.EXE" ] && JOINT_VERIFY="$JOINT_VERIFY ${_vp}\$SHR.EXE" + done for jn in $JOINT_VERIFY; do grep -qi "$jn" /work/distrib-list.txt \ || { echo "FAIL: mastered ODS-2 image missing JOINT-E2E proof file $jn"; exit 1; } diff --git a/tools/cross-alpha/run-module-gp-activation-alpha.sh b/tools/cross-alpha/run-module-gp-activation-alpha.sh index 42f21e03..3422c463 100755 --- a/tools/cross-alpha/run-module-gp-activation-alpha.sh +++ b/tools/cross-alpha/run-module-gp-activation-alpha.sh @@ -384,10 +384,17 @@ build_joint_images() { # $WORK/joint is exactly the signal build-alpha-bootimage.sh keys on to stage the # producer into SYS$SHARE + swap in the VENEER-proof SYSTARTUP. if [ "$JOINT_CRTL_RMS_VENEER" = 1 ]; then - [ -s "$out_n3/LIBVMSRMS\$SHR.EXE" ] \ - || die "veneer build produced no LIBVMSRMS\$SHR.EXE in $out_n3 (JOINT_CRTL_RMS_VENEER=1 expected it)" - cp "$out_n3/LIBVMSRMS\$SHR.EXE" "$WORK/joint/LIBVMSRMS\$SHR.EXE" - log "step 1: joint images staged into $WORK/joint (VENEER milestone N=$WANT_SENTINEL + control + DECC\$SHR/LIBOTS/LIBVMSRMS\$SHR producers)" + # vms-f49: the veneer image needs the FULL executive producer graph on + # SYS$SHARE at activation, not just LIBVMSRMS$SHR -- LIBVMSRMS$SHR imports + # (transitively) from LIBVMS/LIBVMSFS/LIBVMSLNM/LIBVMSPROCESS/LIBVMSSYS$SHR. + # build-joint-image.sh emits all of them to $out_n3; stage each into + # $WORK/joint so build-alpha-bootimage.sh masters them onto the ODS-2 volume. + for _p in LIBVMSRMS LIBVMS LIBVMSFS LIBVMSLNM LIBVMSPROCESS LIBVMSSYS; do + [ -s "$out_n3/${_p}\$SHR.EXE" ] \ + || die "veneer build produced no ${_p}\$SHR.EXE in $out_n3 (JOINT_CRTL_RMS_VENEER=1 expected the full producer graph)" + cp "$out_n3/${_p}\$SHR.EXE" "$WORK/joint/${_p}\$SHR.EXE" + done + log "step 1: joint images staged into $WORK/joint (VENEER milestone N=$WANT_SENTINEL + control + DECC\$SHR/LIBOTS + full RMS producer graph LIBVMSRMS/LIBVMS/LIBVMSFS/LIBVMSLNM/LIBVMSPROCESS/LIBVMSSYS\$SHR)" else log "step 1: joint images staged into $WORK/joint (milestone N=$WANT_SENTINEL + SS\$_NORMAL control + producers)" fi From 41f9e0021f33fcde27112b01755985a76f60f8f3 Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 20:12:58 +0000 Subject: [PATCH 04/13] vms-f49: surface the guest-kernel faulting PC in the veneer-gate failure output The veneer image now activates (producer graph staged) but SIGSEGVs (%DCL-F-ABORT signal 11) in the first-ever runtime execution of the alpha RMS substrate over the veneer. The Alpha guest kernel prints the faulting user PC/RA/VA to the console at fault time, but the gate's fixed pattern-grep never surfaced it. Dump the guest fault-signature line(s) + the last 60 console lines in the veneer-gate FAIL path so the authoritative fault PC is captured in CI (disk-safe -- no qemu -d flags; the guest kernel already emitted it). This localizes the crash so it can be fixed. Not a gate weakening -- failure path only. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- tools/cross-alpha/run-module-gp-activation-alpha.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tools/cross-alpha/run-module-gp-activation-alpha.sh b/tools/cross-alpha/run-module-gp-activation-alpha.sh index 3422c463..db7dcd77 100755 --- a/tools/cross-alpha/run-module-gp-activation-alpha.sh +++ b/tools/cross-alpha/run-module-gp-activation-alpha.sh @@ -811,6 +811,18 @@ EOF echo " pointer symptom (Part A) -- the veneer ioctl(/dev/vms) landed on a bad address." echo " Full log: $WORK/modgpA.log" grep -aE "VENEER-PROOF:|%IMGACT|%RUN-|%DCL-|IMGNOTFND|NOSUCHFILE|DEVNOTMOUNT|ACCVIO|%DIRECT|SS\\\$_" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -25 || echo " (none captured)" + # vms-f49 fault-capture: when the veneer image SIGSEGVs (%DCL-F-ABORT signal + # 11), the Alpha guest kernel prints the faulting USER pc/ra/va to the console + # (arch/alpha/mm/fault.c show_unhandled_signals: ": memory violation ... + # pc=... ra=..."). The gate's pattern grep above does not surface it, so dump + # the guest fault line(s) + the crash-context tail explicitly -- this is the + # authoritative fault PC for localizing the crash (gdb-equivalent, per the + # alpha-rail fault-capture discipline). No qemu -d flags (disk-safe): the guest + # kernel already emitted it into the captured console. + echo "--- guest-kernel fault signature (faulting user PC/RA/VA) ---" + grep -aiE "memory violation|segmentation|segfault|unaligned| pc ?=?0x?[0-9a-f]| ra ?=?0x?[0-9a-f]|Oops|BUG:|kernel access|access to| va ?=?0x?[0-9a-f]|SIGSEGV|bad address|panic" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -30 || echo " (no guest fault line captured)" + echo "--- last 60 console lines around the crash ---" + tail -60 "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ | /' || true exit 1 ;; *) From c99fdae2cc4ddf654511c85549ed08ca07c7e824 Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 20:38:09 +0000 Subject: [PATCH 05/13] vms-f49: capture qemu CPU-exception log to pin the veneer SIGSEGV faulting PC The previous fault-capture confirmed the veneer image crashes at/near ACTIVATION (no OVMX-CRTL-RMS sys$create trace precedes the %DCL-F-ABORT signal 11), and the Alpha guest kernel prints no userspace fault line. So add qemu exception logging (-d int,cpu_reset,guest_errors -D /work/qint.log), enabled ONLY for the crtl-rms-veneer-gate via QEMU_DBG, and dump the last exceptions (faulting PC/VA) in the veneer FAIL path. Disk-safe: the boot reaches Username: within ~30-60s so qint.log stays small; other gates pass QEMU_DBG empty (unchanged). This is the gdb-equivalent authoritative fault PC needed to decide RMS-substrate truncation (hyp 1) vs IMGACT mutual-producer-cycle activation crash (hyp 2, the leading hypothesis: the veneer DECC$SHR<->LIBVMSRMS$SHR cycle the non-veneer control lacks). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- .../run-module-gp-activation-alpha.sh | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/tools/cross-alpha/run-module-gp-activation-alpha.sh b/tools/cross-alpha/run-module-gp-activation-alpha.sh index db7dcd77..d8726e54 100755 --- a/tools/cross-alpha/run-module-gp-activation-alpha.sh +++ b/tools/cross-alpha/run-module-gp-activation-alpha.sh @@ -421,8 +421,15 @@ assemble_boot_image() { # open long enough for STDRV to finish, then capture the filtered console log. # --------------------------------------------------------------------------- run_boot_a() { - rm -f "$WORK/modgpA.img" "$WORK/modgpA.raw" "$WORK/modgpA.log" "$WORK/modgpA.fifo" + rm -f "$WORK/modgpA.img" "$WORK/modgpA.raw" "$WORK/modgpA.log" "$WORK/modgpA.fifo" "$WORK/qint.log" local cname="ovmx-alpha-modgp-$$" + # vms-f49 fault-capture: QEMU_DBG (set only by crtl-rms-veneer-gate) injects + # qemu exception logging so the veneer SIGSEGV's faulting PC/VA is recorded. + # The Alpha guest kernel does not print a userspace fault line, and the crash + # is at/near activation (before any veneer stderr trace), so this is the only + # way to pin the PC. Bounded/disk-safe: the boot reaches Username: within + # ~30-60s (the wait loop then kills qemu), so qint.log stays small. + local qdbg="${QEMU_DBG:-}" set +e timeout --kill-after="$TIMEOUT_GRACE" "$DOCKER_TIMEOUT" docker run --rm \ --name "$cname" --memory=8g --cpus="$(nproc)" \ @@ -437,6 +444,7 @@ run_boot_a() { timeout "$BT" qemu-system-alpha -M clipper -smp 1 -m 1024 -vga none -nic none \ -kernel vmlinux-boot -append "console=ttyS0 panic=-1 OVMX_IMGACT_SEAM=1" \ -drive file=modgpA.img,format=raw,if=virtio \ + '"$qdbg"' \ -nographic -no-reboot <"$FIFO" > modgpA.raw 2>&1 & QP=$! exec 6>"$FIFO" @@ -786,7 +794,10 @@ EOF build_joint_images assemble_boot_image log "step 3: BOOT A -- activate the VENEER crtl_rms image + run the INDEPENDENT DIRECTORY reader on the REAL executive" - run_boot_a + # vms-f49 fault-capture: log qemu CPU exceptions so the veneer SIGSEGV's + # faulting PC/VA is recorded (the guest kernel prints no user fault line, and + # the crash is at/near activation). Bounded (boot reaches Username: fast). + QEMU_DBG="-d int,cpu_reset,guest_errors -D /work/qint.log" run_boot_a echo "" echo "========================================================================" echo "== vms-f49 rung 4: CRTL->RMS veneer -> real ODS-2 landing, PROVEN by an" @@ -823,6 +834,16 @@ EOF grep -aiE "memory violation|segmentation|segfault|unaligned| pc ?=?0x?[0-9a-f]| ra ?=?0x?[0-9a-f]|Oops|BUG:|kernel access|access to| va ?=?0x?[0-9a-f]|SIGSEGV|bad address|panic" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -30 || echo " (no guest fault line captured)" echo "--- last 60 console lines around the crash ---" tail -60 "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ | /' || true + # vms-f49: the qemu CPU-exception log pins the faulting PC/VA of the veneer + # SIGSEGV (guest kernel emits no user fault line; crash is at/near activation). + if [ -f "$WORK/qint.log" ]; then + echo "--- qemu exception log: size $(wc -c <"$WORK/qint.log" 2>/dev/null) bytes; last exceptions (faulting PC/VA) ---" + grep -anE 'Abort|Access|MM_FAULT|D-fault|I-fault|fault|violation|PALcode|pc[ =]|EXCEPTION|Unaligned|GENTRAP|OPCDEC|mm fault|Taking exception|v0=|pc =0x|pc=0x' "$WORK/qint.log" 2>/dev/null | tail -40 | sed 's/^/ q| /' || true + echo "--- qemu exception log: raw tail (last 60 lines) ---" + tail -60 "$WORK/qint.log" 2>/dev/null | sed 's/^/ q| /' || true + else + echo "--- (no qemu exception log captured) ---" + fi exit 1 ;; *) From ba562f53f11a25c78435048f38abd4f63efc2fe3 Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 20:50:43 +0000 Subject: [PATCH 06/13] vms-f49: filter qemu exception log (clk-interrupt firehose hid the fault) The -d int log is dominated by clk_interrupt; the veneer SIGSEGV's Dfault/MMFAULT exception with the faulting user pc= is buried. Filter out clk/dev interrupts and add an exception-type histogram so the fault exception + PC is surfaced. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- tools/cross-alpha/run-module-gp-activation-alpha.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tools/cross-alpha/run-module-gp-activation-alpha.sh b/tools/cross-alpha/run-module-gp-activation-alpha.sh index d8726e54..87a15098 100755 --- a/tools/cross-alpha/run-module-gp-activation-alpha.sh +++ b/tools/cross-alpha/run-module-gp-activation-alpha.sh @@ -837,10 +837,14 @@ EOF # vms-f49: the qemu CPU-exception log pins the faulting PC/VA of the veneer # SIGSEGV (guest kernel emits no user fault line; crash is at/near activation). if [ -f "$WORK/qint.log" ]; then - echo "--- qemu exception log: size $(wc -c <"$WORK/qint.log" 2>/dev/null) bytes; last exceptions (faulting PC/VA) ---" - grep -anE 'Abort|Access|MM_FAULT|D-fault|I-fault|fault|violation|PALcode|pc[ =]|EXCEPTION|Unaligned|GENTRAP|OPCDEC|mm fault|Taking exception|v0=|pc =0x|pc=0x' "$WORK/qint.log" 2>/dev/null | tail -40 | sed 's/^/ q| /' || true - echo "--- qemu exception log: raw tail (last 60 lines) ---" - tail -60 "$WORK/qint.log" 2>/dev/null | sed 's/^/ q| /' || true + echo "--- qemu exception log: size $(wc -c <"$WORK/qint.log" 2>/dev/null) bytes ---" + # Filter the clk/dev interrupt firehose; the userspace SIGSEGV shows up as + # an MMFAULT/DFAULT/DTBMISS/OPCDEC/ARITH/UNALIGN exception with the faulting + # user pc= just before the process dies. Show the last such real exceptions. + echo "--- non-interrupt exceptions (the fault is here; last 60) ---" + grep -avE 'clk_interrupt|dev_interrupt|smp_' "$WORK/qint.log" 2>/dev/null | tail -60 | sed 's/^/ q| /' || true + echo "--- exception-type histogram (which exceptions fired) ---" + grep -aoE 'INT +[0-9]+: *[a-zA-Z_]+' "$WORK/qint.log" 2>/dev/null | sed -E 's/INT +[0-9]+: *//' | sort | uniq -c | sort -rn | head -20 | sed 's/^/ q| /' || true else echo "--- (no qemu exception log captured) ---" fi From e55e5df505035ed24f62c310919213c0eb4cc035 Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 21:02:49 +0000 Subject: [PATCH 07/13] vms-f49: IMGACT-MAP producer base logging to resolve the veneer fault PC The qemu -d int log localized the veneer SIGSEGV to a repeated mmfault loop at user pc=0x12005eb00 (and 0x12005a7f4). IMGACT is only ~37KB so the fault is in a mmap'd producer (likely DECC$SHR, which holds the veneer ovmx_crtl_fopen). Print each producer's runtime base (IMGACT-MAP: base=0x..) at load so the faulting pc can be resolved to +offset and then to a symbol. Diagnostic only; other gates grep their own patterns so the extra lines are inert. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- src/imgact/imgact.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/imgact/imgact.c b/src/imgact/imgact.c index a50d9db0..e71d230e 100644 --- a/src/imgact/imgact.c +++ b/src/imgact/imgact.c @@ -303,6 +303,26 @@ int strncmp(const char *a, const char *b, unsigned long n) static void eputs(const char *s) { sys_write(2, s, xstrlen(s)); } +/* vms-f49 fault-localization: print a mapped image's runtime base so a qemu + * -d int faulting user pc can be resolved to +offset. Unconditional but + * cheap (one line per producer at activation); the activation gates grep for + * their own patterns, so the extra "IMGACT-MAP:" lines are inert there. */ +static void imgact_dbg_map(const char *name, unsigned long base) +{ + static const char H[] = "0123456789abcdef"; + char hx[17]; + for (int i = 0; i < 16; i++) hx[15 - i] = H[(base >> (i * 4)) & 0xf]; + hx[16] = 0; + char line[192]; + line[0] = 0; + xstrcat(line, "IMGACT-MAP: "); + xstrcat(line, name); + xstrcat(line, " base=0x"); + xstrcat(line, hx); + xstrcat(line, "\n"); + eputs(line); +} + /* Defined further down; forward-declared here because imgact_vms_exit (which * precedes the definition) reads it for the OVMX_IMGACT_SEAM $STATUS readback. */ static const char *imgact_env_value(char **envp, const char *key); @@ -1574,6 +1594,7 @@ static struct ovmx_prod *load_ovmx_producer(const char *soname) struct ovmx_prod *p = &g_prods[g_nprods++]; xstrcpy(p->name, soname); p->base = base; + imgact_dbg_map(soname, base); /* vms-f49 fault-localization */ p->sv = (const struct ovmx_sv_header *)(base + sv_addr); if (p->sv->magic != OVMX_SV_MAGIC) { g_nprods--; return 0; } From bd2d456e32baa5ac4488e75282dd6b700715889d Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 21:15:39 +0000 Subject: [PATCH 08/13] vms-f49: log MAIN-EXE + IMGACT-INTERP bases to place the 0x120000000 fault region Producer bases are all 0x20000xxxxx, but the veneer fault PCs cluster in the 0x120000000 range (0x12005eb00 repeated 18x = the unrecoverable fault; other single-hit pcs are benign TLB fills). Log the kernel-mapped main-exe bias and the PT_INTERP (IMGACT) base so the faulting region can be attributed to the main image, the interp, or an unmapped bad-jump target (mis-resolved cross-image linkage = hyp 2). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- src/imgact/imgact.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/imgact/imgact.c b/src/imgact/imgact.c index e71d230e..77f8f235 100644 --- a/src/imgact/imgact.c +++ b/src/imgact/imgact.c @@ -2856,6 +2856,8 @@ unsigned long imgact_bootstrap(unsigned long *sp) Elf64_Phdr *ephdr = (Elf64_Phdr *)at_phdr; int ephnum = (int)at_phnum; unsigned long ebias = exec_bias(ephdr, ephnum, at_phdr); + imgact_dbg_map("MAIN-EXE", ebias); /* vms-f49 */ + imgact_dbg_map("IMGACT-INTERP", imgact_getauxval(7 /*AT_BASE*/)); /* vms-f49 */ Elf64_Dyn *edyn = 0; for (int i = 0; i < ephnum; i++) From 261e9109df38e8bac18ea56bfbefb9d5022fef76 Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 21:38:33 +0000 Subject: [PATCH 09/13] vms-f49: gate IMGACT-MAP behind OVMX_IMGACT_MAP=1 (silent by default) Housekeeping: the IMGACT-MAP producer-base logging now emits only when the boot cmdline carries OVMX_IMGACT_MAP=1 (kept for fault-localization, silent in production). run_boot_a gains an optional QEMU_APPEND injection; the veneer gate sets QEMU_APPEND=OVMX_IMGACT_MAP=1 so it still gets the map. The QEMU_DBG -d int fault capture is retained (inert for other gates). Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- src/imgact/imgact.c | 10 ++++++++++ tools/cross-alpha/run-module-gp-activation-alpha.sh | 8 ++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/imgact/imgact.c b/src/imgact/imgact.c index 77f8f235..4f74e0d4 100644 --- a/src/imgact/imgact.c +++ b/src/imgact/imgact.c @@ -303,12 +303,22 @@ int strncmp(const char *a, const char *b, unsigned long n) static void eputs(const char *s) { sys_write(2, s, xstrlen(s)); } +/* Forward decls so imgact_dbg_map (below) can gate on OVMX_IMGACT_MAP. */ +static const char *imgact_env_value(char **envp, const char *key); +static char **g_envp; + /* vms-f49 fault-localization: print a mapped image's runtime base so a qemu * -d int faulting user pc can be resolved to +offset. Unconditional but * cheap (one line per producer at activation); the activation gates grep for * their own patterns, so the extra "IMGACT-MAP:" lines are inert there. */ static void imgact_dbg_map(const char *name, unsigned long base) { + /* Silent by default; opt in with OVMX_IMGACT_MAP=1 in the boot append line + * (vms-f49 fault-localization -- do not emit on every activation for all + * images in production). */ + const char *want = imgact_env_value(g_envp, "OVMX_IMGACT_MAP"); + if (!want || want[0] != '1') + return; static const char H[] = "0123456789abcdef"; char hx[17]; for (int i = 0; i < 16; i++) hx[15 - i] = H[(base >> (i * 4)) & 0xf]; diff --git a/tools/cross-alpha/run-module-gp-activation-alpha.sh b/tools/cross-alpha/run-module-gp-activation-alpha.sh index 87a15098..5d64ef33 100755 --- a/tools/cross-alpha/run-module-gp-activation-alpha.sh +++ b/tools/cross-alpha/run-module-gp-activation-alpha.sh @@ -430,6 +430,10 @@ run_boot_a() { # way to pin the PC. Bounded/disk-safe: the boot reaches Username: within # ~30-60s (the wait loop then kills qemu), so qint.log stays small. local qdbg="${QEMU_DBG:-}" + # QEMU_APPEND (set only by crtl-rms-veneer-gate) adds kernel cmdline tokens -- + # e.g. OVMX_IMGACT_MAP=1 to turn on IMGACT-MAP producer-base logging, which is + # silent by default (vms-f49 housekeeping). + local qappend="${QEMU_APPEND:-}" set +e timeout --kill-after="$TIMEOUT_GRACE" "$DOCKER_TIMEOUT" docker run --rm \ --name "$cname" --memory=8g --cpus="$(nproc)" \ @@ -442,7 +446,7 @@ run_boot_a() { # activated image (GETEXIT(SEL_SELF)); the DCL RUN fork path collapses the # POSIX exit, so the seam is the truth for the returned value. timeout "$BT" qemu-system-alpha -M clipper -smp 1 -m 1024 -vga none -nic none \ - -kernel vmlinux-boot -append "console=ttyS0 panic=-1 OVMX_IMGACT_SEAM=1" \ + -kernel vmlinux-boot -append "console=ttyS0 panic=-1 OVMX_IMGACT_SEAM=1 '"$qappend"'" \ -drive file=modgpA.img,format=raw,if=virtio \ '"$qdbg"' \ -nographic -no-reboot <"$FIFO" > modgpA.raw 2>&1 & @@ -797,7 +801,7 @@ EOF # vms-f49 fault-capture: log qemu CPU exceptions so the veneer SIGSEGV's # faulting PC/VA is recorded (the guest kernel prints no user fault line, and # the crash is at/near activation). Bounded (boot reaches Username: fast). - QEMU_DBG="-d int,cpu_reset,guest_errors -D /work/qint.log" run_boot_a + QEMU_DBG="-d int,cpu_reset,guest_errors -D /work/qint.log" QEMU_APPEND="OVMX_IMGACT_MAP=1" run_boot_a echo "" echo "========================================================================" echo "== vms-f49 rung 4: CRTL->RMS veneer -> real ODS-2 landing, PROVEN by an" From cfc668d5eed4f9c99f0510359bc8737c1554b047 Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 22:21:49 +0000 Subject: [PATCH 10/13] =?UTF-8?q?vms-f49:=20Option-1=20probe=20=E2=80=94?= =?UTF-8?q?=20log=20wild=20(0x120000000-region)=20import=20bindings=20in?= =?UTF-8?q?=20IMGACT?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The veneer SIGSEGV jumps to 0x120000000+offset (default/stack-top base) while all images map at 0x200_xxxx_xxxx; the value is COMPUTED at runtime (not stored). Add a gated (OVMX_IMGACT_MAP=1) probe in bind_imports that logs any binding whose resolved PV or filled code entry *(PV+8) lands in the wild region -- with the importing image, the symbol, the cell, the PV, and the entry. A wild PV isolates an SV-value fault; a sane PV with a wild entry isolates a producer PDSC-entry rebase fault. Surface IMGACT-WILD/IMGACT-MAP in the veneer-gate failure dump. If nothing fires, the wild target is code/GP-computed (not a linkage fill) and the next step is a register (RA) capture. Probe only; no behavior change. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- src/imgact/imgact.c | 45 +++++++++++++++++++ .../run-module-gp-activation-alpha.sh | 2 + 2 files changed, 47 insertions(+) diff --git a/src/imgact/imgact.c b/src/imgact/imgact.c index 4f74e0d4..cc494e46 100644 --- a/src/imgact/imgact.c +++ b/src/imgact/imgact.c @@ -333,6 +333,42 @@ static void imgact_dbg_map(const char *name, unsigned long base) eputs(line); } +/* vms-f49 Option-1 probe: log an import binding whose resolved PV or filled code + * entry lands in the wild 0x1_0000_0000..0x200_0000_0000 region (all real images + * map at 0x200_xxxx_xxxx; the veneer SIGSEGV jumps to 0x120000000+offset). Gated + * on OVMX_IMGACT_MAP=1. Prints who imports what, the cell, the PV (=PDSC), and + * the code entry *(PV+8) actually written -- so a wild PV vs a wild-only entry + * distinguishes an SV-value fault from a producer PDSC-entry rebase fault. */ +static void imgact_dbg_hexline(const char *tag, const char *a, const char *b, + unsigned long v1, unsigned long v2, unsigned long v3) +{ + const char *want = imgact_env_value(g_envp, "OVMX_IMGACT_MAP"); + if (!want || want[0] != '1') + return; + static const char H[] = "0123456789abcdef"; + char line[320]; + line[0] = 0; + xstrcat(line, tag); + if (a) { xstrcat(line, a); } + if (b) { xstrcat(line, " imports "); xstrcat(line, b); } + const char *labs[3] = { " cell=0x", " pv=0x", " entry=0x" }; + unsigned long vs[3] = { v1, v2, v3 }; + for (int j = 0; j < 3; j++) { + char hx[17]; + for (int i = 0; i < 16; i++) hx[15 - i] = H[(vs[j] >> (i * 4)) & 0xf]; + hx[16] = 0; + xstrcat(line, labs[j]); + xstrcat(line, hx); + } + xstrcat(line, "\n"); + eputs(line); +} + +static inline int imgact_addr_is_wild(unsigned long v) +{ + return v >= 0x100000000UL && v < 0x200000000000UL; +} + /* Defined further down; forward-declared here because imgact_vms_exit (which * precedes the definition) reads it for the OVMX_IMGACT_SEAM $STATUS readback. */ static const char *imgact_env_value(char **envp, const char *key); @@ -1782,6 +1818,15 @@ static void bind_imports(unsigned long base, const struct ovmx_imp_header *ih, sys_exit(IMGACT_EXIT_FAIL); } imgact_fill_import(base + ie[k].patch_off, PV, linkage, codeaddr); + /* vms-f49 Option-1 probe: catch a binding that resolves/writes into the + * wild 0x120000000-region (the veneer SIGSEGV target). PV wild -> SV-value + * fault; PV sane but entry *(PV+8) wild -> producer PDSC-entry rebase fault. */ + { + unsigned long _entry = (linkage || codeaddr) ? imgact_sv_code_entry(PV) : PV; + if (imgact_addr_is_wild(PV) || imgact_addr_is_wild(_entry)) + imgact_dbg_hexline("IMGACT-WILD: ", whoami, soname, + base + ie[k].patch_off, PV, _entry); + } #else unsigned long addr = ovmx_sv_resolve(p->sv, ie[k].sv_index, p->base, ie[k].req_major, ie[k].req_minor); diff --git a/tools/cross-alpha/run-module-gp-activation-alpha.sh b/tools/cross-alpha/run-module-gp-activation-alpha.sh index 5d64ef33..5ae32792 100755 --- a/tools/cross-alpha/run-module-gp-activation-alpha.sh +++ b/tools/cross-alpha/run-module-gp-activation-alpha.sh @@ -836,6 +836,8 @@ EOF # kernel already emitted it into the captured console. echo "--- guest-kernel fault signature (faulting user PC/RA/VA) ---" grep -aiE "memory violation|segmentation|segfault|unaligned| pc ?=?0x?[0-9a-f]| ra ?=?0x?[0-9a-f]|Oops|BUG:|kernel access|access to| va ?=?0x?[0-9a-f]|SIGSEGV|bad address|panic" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -30 || echo " (no guest fault line captured)" + echo "--- IMGACT-MAP bases + IMGACT-WILD bindings (vms-f49 Option-1 probe) ---" + grep -aE "IMGACT-WILD|IMGACT-MAP" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -40 || echo " (none -- wild value is code/GP-computed, not a linkage fill)" echo "--- last 60 console lines around the crash ---" tail -60 "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ | /' || true # vms-f49: the qemu CPU-exception log pins the faulting PC/VA of the veneer From c177632ef4638ecb4b1bd7a0a3552ea2212b630f Mon Sep 17 00:00:00 2001 From: alice Date: Mon, 7 Sep 2026 22:36:15 +0000 Subject: [PATCH 11/13] vms-f49: correct the Option-1 probe wild-region range (0x1_xx, not the 0x200xxx image region) The probe flagged all valid 0x200_xxxx_xxxx bindings as wild because the upper bound (0x200000000000) sat above the real image region. Narrow it to [0x1_0000_0000, 0x100_0000_0000) -- the 0x120000000 default/stack-top region -- so only genuinely-wild values fire. Confirmed against the CI run: with the correct range NO binding is wild (all PVs/entries resolve to 0x200xxx), proving the veneer SIGSEGV is NOT a linkage fill but a wrong-base code jump. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- src/imgact/imgact.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/imgact/imgact.c b/src/imgact/imgact.c index cc494e46..af039741 100644 --- a/src/imgact/imgact.c +++ b/src/imgact/imgact.c @@ -366,7 +366,11 @@ static void imgact_dbg_hexline(const char *tag, const char *a, const char *b, static inline int imgact_addr_is_wild(unsigned long v) { - return v >= 0x100000000UL && v < 0x200000000000UL; + /* The wild region is the Alpha default/stack-top base ~0x120000000 (the + * veneer SIGSEGV target); real images map far higher, at 0x200_xxxx_xxxx + * (~2.2e12). So flag [0x1_0000_0000, 0x100_0000_0000) -- above a small + * absolute yet BELOW the real image region. */ + return v >= 0x100000000UL && v < 0x10000000000UL; } /* Defined further down; forward-declared here because imgact_vms_exit (which From e2c6cf5ef5b1f734e549eeb0d4590d967d710e27 Mon Sep 17 00:00:00 2001 From: alice Date: Tue, 8 Sep 2026 14:06:24 +0000 Subject: [PATCH 12/13] =?UTF-8?q?vms-f49:=20fix=20emutls=20control-object?= =?UTF-8?q?=20width=20(LLP64)=20=E2=80=94=20the=20veneer=20rung-4=20crash?= =?UTF-8?q?=20root=20cause?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The alpha emulated-TLS runtime typed the control-object fields as `unsigned long` (emutls_word), which on the alpha-dec-vms LLP64 target is 32 BITS — but the cc1 emits the control with 64-bit .quad fields (.quad size; .quad align; .quad loc; .quad templ). So struct __emutls_object packed size+align into the first 8 bytes and put `loc` at offset 8 (the align field) instead of 16. __emutls_get_address returned obj->loc = the align value (4), and the first __thread access on the veneer's sys$create path (a vms_kif 'vms_bound_pid == getpid()' check) then dereferenced 4 -> SIGSEGV at 0x4 — the rung-4 (vms-f49) blocker, pinned via a local qemu-system-alpha boot + an IMGACT SIGSEGV-handler RA capture. Fix: emutls_word -> unsigned long long (64-bit on every target), so loc lands at offset 16 and templ at 24, matching the .quad emission. Same LLP64 bug class as vms-1fc. Arch-scoped: the whole file is #if defined(__alpha__), so x86_64/aarch64 (musl TLS) and VAX (NetBSD) never compile it — the non-veneer + VAX/x86_64 controls stay byte-identical. Verified locally: the v0=4 / gp-as-stack SIGSEGV is gone; the veneer image now advances past the emutls point into the Files-11 path. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- src/libvmssys/arch/alpha/emutls_vms.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/libvmssys/arch/alpha/emutls_vms.c b/src/libvmssys/arch/alpha/emutls_vms.c index f356142a..5beab056 100644 --- a/src/libvmssys/arch/alpha/emutls_vms.c +++ b/src/libvmssys/arch/alpha/emutls_vms.c @@ -46,12 +46,22 @@ extern void *memset(void *, int, unsigned long); /* The control object the compiler emits, in emission order. `word` is pointer- * width (8 bytes on this LP64-kernel/LLP64-compiler target: the .quad fields * above are 64-bit). */ -typedef unsigned long emutls_word; +/* vms-f49 (rung 4): each control field the alpha-dec-vms cc1 emits is a `.quad` + * (64-bit) -- `__emutls_v.x: .quad size ; .quad align ; .quad loc ; .quad templ` + * (verified from generated assembly). emutls_word MUST therefore be 64-bit so + * `loc` lands at struct offset 16 and `templ` at 24, matching the emission. It + * was `unsigned long`, which on this LLP64 target is 32 BITS (same class as the + * vms-1fc width bug) -- that packed size+align into the first 8 bytes and put + * `loc` at offset 8 (the align field). __emutls_get_address then returned the + * align value (4) as the TLS pointer, and the first __thread access on the + * veneer's sys$create path dereferenced 4 -> SIGSEGV (the rung-4 blocker). Use + * `unsigned long long` (guaranteed 64-bit on every target) to match the .quad. */ +typedef unsigned long long emutls_word; struct __emutls_object { - emutls_word size; /* bytes of the __thread object */ - emutls_word align; /* required alignment */ - void *loc; /* runtime-owned storage pointer (init 0) */ - void *templ; /* initializer image, or 0 => zero-init */ + emutls_word size; /* bytes of the __thread object (.quad, offset 0) */ + emutls_word align; /* required alignment (.quad, offset 8) */ + void *loc; /* runtime-owned storage pointer (.quad, offset 16) */ + void *templ; /* initializer image, 0=>zero (.quad, offset 24) */ }; void *__emutls_get_address(struct __emutls_object *obj) From 04c690e630af052be9a460ed21489125417e8f40 Mon Sep 17 00:00:00 2001 From: alice Date: Tue, 8 Sep 2026 15:28:10 +0000 Subject: [PATCH 13/13] vms-f49: un-fakeable ODS-2 landing proof (rung 4) + bug #2/#3 toolchain fixes; strip diagnostics Rung 4 of the vms-b4f ladder. Boots the CRTL->RMS veneer-wired alpha-dec-vms GCC-port image on qemu-system-alpha + the real /dev/vms executive: its decc$fopen -> ovmx_crtl veneer -> sys$create -> LIBVMSRMS$SHR -> ioctl(/dev/vms) -> Files-11 ACP writes PORTTEST.DAT, then an INDEPENDENT reader (DCL DIRECTORY/FULL, a different accessor than the writer's own CRTL/RMS handle) asserts PORTTEST.DAT;1 landed on the real ODS-2 volume with a genuine File ID AND the full 8192-byte content (16 blocks) -- something a ramfs/POSIX write can never produce in the ACP directory. The gate keys on that fid+content landing (strictly stronger than a same-CRTL round-trip a ramfs satisfies), with a 7/7 can-fail selftest. Three first-exercise toolchain bugs the forcing function exposed: - #1 emutls control-object width (LLP64): unsigned long is 32-bit on alpha-dec-vms, so __emutls_object {size,align,loc,templ} packed loc at offset 8 instead of 16 and __emutls_get_address returned 4 -> SIGSEGV. emutls_word widened to unsigned long long. (committed earlier as e2c6cf5e) - #2 DECC$SHR symbol-vector index skew (mk_decc_shr.sh): the veneer pass dropped the 4 fopen/fwrite/fread/fclose entries from the middle of the sorted vector and re-appended the aliases at the tail, shifting every higher sv# down by 4. IMGACT binds cross-image imports BY INDEX, so producers linked against the bootstrap DECC dispatched e.g. decc$strlen[sv#414] to decc$strspn at runtime (NULL-arg SIGSEGV). Rewrite the 4 entries IN PLACE at their sorted slot, restoring the append-only sv# stability the recipe already documented. - #3 calloc weak-override reloc (link.c): the vms-430 strong-over-weak base-redirect matched a section-relative reloc's section BASE before the addend was added, so every sibling symbol in a $CODE$ whose offset-0 proc is an overridden weak def (calloc.o's __malloc_allzerop) was pulled onto the strong def + addend -- decc$_calloc64 (real calloc at $CODE$+0x008) mis-bound onto strong __malloc_allzerop+0x008. Match base+addend and consume the addend on a hit; the symbol-target path is byte-identical. run_muldef_evax.sh green (incl. weak-first + strong-first self-bind redirect). All diagnostic scaffolding stripped (IMGACT SIGSEGV handler / IMGACT-MAP probe / qemu -d int injection) for a clean production activator. The writer program's post-commit mallocng cleanup crash (free -> free_group -> free(g->mem) hitting get_meta's `assert(meta->mem==base)` with a NULL group meta) is a separate mallocng-group-release issue on the alpha-dec-vms substrate, tracked as bug #4 (blocks vms-fd1); it fires AFTER the content commits and does not affect the proven landing. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01FJZf62TMXxvy6fXzFQYfLQ --- src/imgact/imgact.c | 82 -------- src/vmslink/link.c | 34 +++- src/vmslink/mk_decc_shr.sh | 46 ++++- .../cross-alpha-vms/joint-e2e/crtl_rms_test.c | 9 + .../joint-e2e/crtl_rms_veneer_test.c | 17 ++ .../SYSTARTUP_VMS_VENEER_PROOF.COM | 19 +- .../run-module-gp-activation-alpha.sh | 179 ++++++++++-------- 7 files changed, 199 insertions(+), 187 deletions(-) create mode 100644 tools/cross-alpha-vms/joint-e2e/crtl_rms_veneer_test.c diff --git a/src/imgact/imgact.c b/src/imgact/imgact.c index af039741..a50d9db0 100644 --- a/src/imgact/imgact.c +++ b/src/imgact/imgact.c @@ -303,76 +303,6 @@ int strncmp(const char *a, const char *b, unsigned long n) static void eputs(const char *s) { sys_write(2, s, xstrlen(s)); } -/* Forward decls so imgact_dbg_map (below) can gate on OVMX_IMGACT_MAP. */ -static const char *imgact_env_value(char **envp, const char *key); -static char **g_envp; - -/* vms-f49 fault-localization: print a mapped image's runtime base so a qemu - * -d int faulting user pc can be resolved to +offset. Unconditional but - * cheap (one line per producer at activation); the activation gates grep for - * their own patterns, so the extra "IMGACT-MAP:" lines are inert there. */ -static void imgact_dbg_map(const char *name, unsigned long base) -{ - /* Silent by default; opt in with OVMX_IMGACT_MAP=1 in the boot append line - * (vms-f49 fault-localization -- do not emit on every activation for all - * images in production). */ - const char *want = imgact_env_value(g_envp, "OVMX_IMGACT_MAP"); - if (!want || want[0] != '1') - return; - static const char H[] = "0123456789abcdef"; - char hx[17]; - for (int i = 0; i < 16; i++) hx[15 - i] = H[(base >> (i * 4)) & 0xf]; - hx[16] = 0; - char line[192]; - line[0] = 0; - xstrcat(line, "IMGACT-MAP: "); - xstrcat(line, name); - xstrcat(line, " base=0x"); - xstrcat(line, hx); - xstrcat(line, "\n"); - eputs(line); -} - -/* vms-f49 Option-1 probe: log an import binding whose resolved PV or filled code - * entry lands in the wild 0x1_0000_0000..0x200_0000_0000 region (all real images - * map at 0x200_xxxx_xxxx; the veneer SIGSEGV jumps to 0x120000000+offset). Gated - * on OVMX_IMGACT_MAP=1. Prints who imports what, the cell, the PV (=PDSC), and - * the code entry *(PV+8) actually written -- so a wild PV vs a wild-only entry - * distinguishes an SV-value fault from a producer PDSC-entry rebase fault. */ -static void imgact_dbg_hexline(const char *tag, const char *a, const char *b, - unsigned long v1, unsigned long v2, unsigned long v3) -{ - const char *want = imgact_env_value(g_envp, "OVMX_IMGACT_MAP"); - if (!want || want[0] != '1') - return; - static const char H[] = "0123456789abcdef"; - char line[320]; - line[0] = 0; - xstrcat(line, tag); - if (a) { xstrcat(line, a); } - if (b) { xstrcat(line, " imports "); xstrcat(line, b); } - const char *labs[3] = { " cell=0x", " pv=0x", " entry=0x" }; - unsigned long vs[3] = { v1, v2, v3 }; - for (int j = 0; j < 3; j++) { - char hx[17]; - for (int i = 0; i < 16; i++) hx[15 - i] = H[(vs[j] >> (i * 4)) & 0xf]; - hx[16] = 0; - xstrcat(line, labs[j]); - xstrcat(line, hx); - } - xstrcat(line, "\n"); - eputs(line); -} - -static inline int imgact_addr_is_wild(unsigned long v) -{ - /* The wild region is the Alpha default/stack-top base ~0x120000000 (the - * veneer SIGSEGV target); real images map far higher, at 0x200_xxxx_xxxx - * (~2.2e12). So flag [0x1_0000_0000, 0x100_0000_0000) -- above a small - * absolute yet BELOW the real image region. */ - return v >= 0x100000000UL && v < 0x10000000000UL; -} - /* Defined further down; forward-declared here because imgact_vms_exit (which * precedes the definition) reads it for the OVMX_IMGACT_SEAM $STATUS readback. */ static const char *imgact_env_value(char **envp, const char *key); @@ -1644,7 +1574,6 @@ static struct ovmx_prod *load_ovmx_producer(const char *soname) struct ovmx_prod *p = &g_prods[g_nprods++]; xstrcpy(p->name, soname); p->base = base; - imgact_dbg_map(soname, base); /* vms-f49 fault-localization */ p->sv = (const struct ovmx_sv_header *)(base + sv_addr); if (p->sv->magic != OVMX_SV_MAGIC) { g_nprods--; return 0; } @@ -1822,15 +1751,6 @@ static void bind_imports(unsigned long base, const struct ovmx_imp_header *ih, sys_exit(IMGACT_EXIT_FAIL); } imgact_fill_import(base + ie[k].patch_off, PV, linkage, codeaddr); - /* vms-f49 Option-1 probe: catch a binding that resolves/writes into the - * wild 0x120000000-region (the veneer SIGSEGV target). PV wild -> SV-value - * fault; PV sane but entry *(PV+8) wild -> producer PDSC-entry rebase fault. */ - { - unsigned long _entry = (linkage || codeaddr) ? imgact_sv_code_entry(PV) : PV; - if (imgact_addr_is_wild(PV) || imgact_addr_is_wild(_entry)) - imgact_dbg_hexline("IMGACT-WILD: ", whoami, soname, - base + ie[k].patch_off, PV, _entry); - } #else unsigned long addr = ovmx_sv_resolve(p->sv, ie[k].sv_index, p->base, ie[k].req_major, ie[k].req_minor); @@ -2915,8 +2835,6 @@ unsigned long imgact_bootstrap(unsigned long *sp) Elf64_Phdr *ephdr = (Elf64_Phdr *)at_phdr; int ephnum = (int)at_phnum; unsigned long ebias = exec_bias(ephdr, ephnum, at_phdr); - imgact_dbg_map("MAIN-EXE", ebias); /* vms-f49 */ - imgact_dbg_map("IMGACT-INTERP", imgact_getauxval(7 /*AT_BASE*/)); /* vms-f49 */ Elf64_Dyn *edyn = 0; for (int i = 0; i < ephnum; i++) diff --git a/src/vmslink/link.c b/src/vmslink/link.c index 2fbf20b8..831e0fa1 100644 --- a/src/vmslink/link.c +++ b/src/vmslink/link.c @@ -3763,9 +3763,31 @@ store_target:; * section-relative linkage-pair quad pointing at the overridden weak def * (e.g. default_malloc's self-bind to __simple_malloc, redirected to * mallocng). No-op for a symbol target (already strong via evax_find_sym) and - * for any address not naming an overridden weak def. */ - S = evax_wredir_apply(redir, nredir, S); - if (have_code) code_S = evax_wredir_apply(redir, nredir, code_S); + * for any address not naming an overridden weak def. + * + * vms-b14: for a SECTION-RELATIVE target the true address is base+addend, so + * the override must match the FULL target, not the section base alone. When + * an overridden weak proc sits at OFFSET 0 of a $CODE$ (calloc.o's weak + * __malloc_allzerop), the section base coincides with that weak entry, and + * redirecting the base pulled EVERY sibling symbol in the section onto the + * strong def + its own addend: decc$_calloc64 (real calloc at $CODE$+0x008) + * was mis-bound onto strong __malloc_allzerop+0x008, so calloc(count,size) + * jumped into the metadata leaf, failed its pointer-alignment assert, and + * a_crash()ed (SIGSEGV at faultVA=0). Match base+addend and, on a hit, use + * the strong def's exact address with the addend CONSUMED (a self-bind that + * targets the weak def itself has addend 0 and is unaffected; a weak def at + * a nonzero offset — which the old base-only match silently missed — now + * redirects correctly). The symbol-target path (to_section < 0) keeps the + * pre-addend base-redirect exactly as before (no-op there anyway). */ + int64_t addend = r->addend; + if (r->to_section >= 0) { + uint64_t full = S + (uint64_t)addend; + uint64_t rt = evax_wredir_apply(redir, nredir, full); + if (rt != full) { S = rt; addend = 0; } /* strong addr is the complete target */ + } else { + S = evax_wredir_apply(redir, nredir, S); + if (have_code) code_S = evax_wredir_apply(redir, nredir, code_S); + } /* Image-relative offset of the store slot (the site), for the .vms$rel table. */ uint64_t rel_site = in[ii].sec_base[r->psect] + r->address; @@ -3776,7 +3798,7 @@ store_target:; switch (r->type) { case EVAX_R_REFLONG: if (r->address + 4 > sec->alloc) die("REFLONG site past psect end"); - putl32(c + r->address, (uint32_t)(S + r->addend)); + putl32(c + r->address, (uint32_t)(S + addend)); /* A REFLONG is a 32-bit slot. If it holds an image-relative address into * a placed section it would need a load-bias fixup — but IMGACT's * .vms$rel loader adds a 64-bit bias to an 8-byte slot, which a 4-byte @@ -3791,13 +3813,13 @@ store_target:; break; case EVAX_R_REFQUAD: if (r->address + 8 > sec->alloc) die("REFQUAD site past psect end"); - putl64(c + r->address, S + r->addend); + putl64(c + r->address, S + addend); if (S_placed) evax_rel_add(rel_off, nrel, rel_cap, rel_site); break; case EVAX_R_CODEADDR: /* Store the target's CODE ENTRY address (a procedure's entry point). */ if (r->address + 8 > sec->alloc) die("CODEADDR site past psect end"); - putl64(c + r->address, (have_code ? code_S : S) + r->addend); + putl64(c + r->address, (have_code ? code_S : S) + addend); if (have_code ? codeS_placed : S_placed) evax_rel_add(rel_off, nrel, rel_cap, rel_site); break; diff --git a/src/vmslink/mk_decc_shr.sh b/src/vmslink/mk_decc_shr.sh index 6c743e5d..5802660d 100755 --- a/src/vmslink/mk_decc_shr.sh +++ b/src/vmslink/mk_decc_shr.sh @@ -142,15 +142,28 @@ if [ "$OVMX_DECC_ARCH" = alpha ]; then # enumeration above just picked up (decc$fopen/fwrite/fread/fclose) are # musl-alpha's OWN POSIX definitions — open()/write() on the raw # Linux-Alpha kernel VFS, never RMS/the executive/the ODS-2 volume - # (trace-grounded, vms-47e). Drop them here so the veneer aliases appended - # further down (decc$fopen/ovmx_crtl_fopen=PROCEDURE, ...) are the ONLY - # vector entry for each of these 4 names — musl's own fopen.o etc stay + # (trace-grounded, vms-47e). REWRITE each in place to its veneer-alias form + # (decc$fopen/ovmx_crtl_fopen=PROCEDURE, ...) — musl's own fopen.o etc stay # whole-archived (dead weight, simply never exported), so this is a # vector-level substitution, never an object-level MULDEF fight (the # veneer's compiled object defines the DISTINCT name `ovmx_crtl_fopen`, # not `decc$fopen` — see the veneer block below for why that is safe). + # + # ⭐ IN-PLACE, NOT delete-and-append (vms-b14). These 4 names sort in the + # MIDDLE of the enumerated vector; deleting them here and re-appending the + # aliases at the tail (as this did before) COMPACTS every higher sv# index + # by 4, so decc$strlen moved sv#414->sv#410 between the bootstrap pass + # (no veneer) and this final pass. IMGACT binds cross-image imports BY + # INDEX (ovmx_sv_resolve on the frozen .vms$imp sv_index), so every + # producer linked against the bootstrap DECC$SHR (LIBVMSFS/LIBVMSRMS/...) + # then dispatched its decc$strlen[sv#414] call to whatever the final + # DECC$SHR put at sv#414 (decc$strspn) — a NULL-a1 SIGSEGV at runtime. + # Real VMS symbol vectors are APPEND-ONLY and NEVER renumbered; rewriting + # the binding in the name's EXISTING slot keeps every sv# stable across the + # two passes (the invariant the veneer block below already documents). if [ -n "${ALPHA_CRTL_RMS_USE:-}" ]; then - grep -vE '^decc\$(fopen|fwrite|fread|fclose)=' "$ALPHA_VEC" > "$ALPHA_VEC.f" + sed -E 's,^decc\$(fopen|fwrite|fread|fclose)=PROCEDURE$,decc$\1/ovmx_crtl_\1=PROCEDURE,' \ + "$ALPHA_VEC" > "$ALPHA_VEC.f" mv "$ALPHA_VEC.f" "$ALPHA_VEC" fi NVEC=$(wc -l < "$ALPHA_VEC") @@ -261,11 +274,18 @@ if [ "$OVMX_DECC_ARCH" = alpha ]; then # ALPHA_CRTL_RMS_USE, exactly as it already runs today). Standard # two-stage bootstrap for the mutual DECC$SHR<->LIBVMSRMS$SHR dependency; # LIBVMSRMS$SHR itself is UNCHANGED and does NOT need rebuilding against - # the veneer-wired DECC$SHR — GSMATCH LEQUAL + NAME-keyed (not - # index-keyed) activation binding (IMGACT's sv_find_named) means every - # universal the bootstrap LIBVMSRMS$SHR already bound (malloc, - # decc$fprintf, ...) stays valid: this pass only ADDS universals or swaps - # an EXISTING name's internal binding in place, never removes/reorders one. + # the veneer-wired DECC$SHR — but ONLY because this pass now preserves the + # symbol-vector INDEX of every universal (the in-place rewrite above), NOT + # because binding is by name. IMGACT resolves cross-image .vms$imp imports + # BY INDEX (ovmx_sv_resolve on the frozen sv_index, imgact.c:1893); only a + # handful of CRTL bootstrap hooks (__init_libc/__copy_tls/...) are looked up + # by name via sv_find_named. So the ONE hard invariant here is append-only, + # never-renumber sv# assignment: this pass ADDS universals at the tail or + # swaps an EXISTING name's internal binding IN PLACE (keeping its slot), and + # never removes/reorders one — because doing so silently mis-binds every + # producer's higher-index decc$ import at activation (vms-b14: a middle-drop + # + tail-append of the 4 veneer names shifted decc$strlen sv#414->sv#410, so + # LIBVMSFS's strlen[sv#414] dispatched to decc$strspn -> NULL-a1 SIGSEGV). # # The wrapper functions are OVMX-original names (ovmx_crtl_fopen, ...), # NOT decc$-decorated: crtl_stdio.h documents that the alpha cc1 does not @@ -303,7 +323,13 @@ if [ "$OVMX_DECC_ARCH" = alpha ]; then done rm -f "$VENEER_VEC" - VEC="$VEC,decc\$fopen/ovmx_crtl_fopen=PROCEDURE,decc\$fwrite/ovmx_crtl_fwrite=PROCEDURE,decc\$fread/ovmx_crtl_fread=PROCEDURE,decc\$fclose/ovmx_crtl_fclose=PROCEDURE" + # NOTE: the decc$fopen/fwrite/fread/fclose -> ovmx_crtl_* alias entries + # are ALREADY in $VEC, rewritten in place at their enumerated sorted + # slot by the ALPHA_CRTL_RMS_USE block above — so the symbol-vector + # index of every OTHER universal is byte-stable vs the bootstrap pass + # (vms-b14). Do NOT re-append them at the tail here: that renumbering is + # exactly the sv# skew that mis-bound LIBVMSFS's decc$strlen to + # decc$strspn at runtime. ALPHA_VENEER_OBJ="$VENEER_OBJ" echo "mk_decc_shr: CRTL->RMS stdio veneer wired: decc\$fopen/fwrite/fread/fclose -> ovmx_crtl_* (--use $ALPHA_CRTL_RMS_USE)" fi diff --git a/tools/cross-alpha-vms/joint-e2e/crtl_rms_test.c b/tools/cross-alpha-vms/joint-e2e/crtl_rms_test.c index bed403ab..5921b355 100644 --- a/tools/cross-alpha-vms/joint-e2e/crtl_rms_test.c +++ b/tools/cross-alpha-vms/joint-e2e/crtl_rms_test.c @@ -51,7 +51,16 @@ extern int fprintf(void *, const char *, ...); extern void *stderr; /* the FILE* stream DATA universal exported by DECC$SHR */ #define PT_SIZE 8192 /* KB-scale buffer */ +/* PT_NAME defaults to a bare filename (the non-veneer N=7 gate's musl-POSIX + * fopen writes it to the ramfs cwd). The veneer variant (crtl_rms_veneer_test.c) + * overrides it with a FULLY-QUALIFIED ODS-2 spec (VDA0:[SYSTMP]PORTTEST.DAT) -- + * matching the host-arch proof (tests/qemu/test_syssvc_crtl_rms_veneer.c uses + * VDA0:[OVMXDIR]VENEER.DAT): under the veneer, fopen routes to sys$create/RMS, + * which needs a device+directory to resolve (a bare name has no default device/ + * dir in the RUN-context process and cannot be resolved). vms-f49. */ +#ifndef PT_NAME #define PT_NAME "PORTTEST.DAT" +#endif int main(int argc, char **argv, char **envp) { diff --git a/tools/cross-alpha-vms/joint-e2e/crtl_rms_veneer_test.c b/tools/cross-alpha-vms/joint-e2e/crtl_rms_veneer_test.c new file mode 100644 index 00000000..71e1e1d0 --- /dev/null +++ b/tools/cross-alpha-vms/joint-e2e/crtl_rms_veneer_test.c @@ -0,0 +1,17 @@ +/* crtl_rms_veneer_test.c (vms-f49, rung 4) — the CRTL/RMS port test with a + * FULLY-QUALIFIED ODS-2 filespec, for the CRTL->RMS veneer gate. + * + * Identical to crtl_rms_test.c (same heap+RMS+stdio round-trip, same sentinel + * ladder) except PT_NAME is a qualified spec: under the veneer, fopen routes to + * sys$create/RMS, which resolves a device+directory. A bare name (crtl_rms_test.c + * default) has no default device/dir in the RUN-context process, so RMS/Files-11 + * cannot resolve it (the resolution path returns no device -> a downstream NULL). + * The host-arch proof (tests/qemu/test_syssvc_crtl_rms_veneer.c) likewise writes + * a qualified VDA0:[OVMXDIR]VENEER.DAT; this is the faithful shape (the proof + * asserts the veneer WRITE lands on the real ODS-2 volume, not default-directory + * resolution). VDA0:[SYSTMP] is the volume's scratch directory (FID (64,1,0), + * mastered by build-alpha-bootimage.sh). The veneer-proof SYSTARTUP's independent + * DIRECTORY/FULL reader queries the same spec. + */ +#define PT_NAME "VDA0:[SYSTMP]PORTTEST.DAT" +#include "crtl_rms_test.c" diff --git a/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM b/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM index 5499c7a6..126cc787 100644 --- a/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM +++ b/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM @@ -24,13 +24,14 @@ $! here is proof the veneer's fopen genuinely landed the file on the real ODS-2 $! volume -- something a same-CRTL fwrite->fread round-trip (which a ramfs $! satisfies identically) can never establish. $! -$! The bare filespec PORTTEST.DAT is deliberate: the port image RUN executes in -$! THIS STDRV process context, so its write and the DIRECTORY below resolve -$! against the identical process default -- whatever that default is, writer and -$! independent reader agree on it. If the LLP64 width fix (vms-1fc) were wrong, -$! the veneer's ioctl(/dev/vms) pointer would truncate, the write would reach -$! nothing, and DIRECTORY would report %DIRECT-W-NOFILES -- the gate reds. That -$! is the whole point: Part A (width) is VALIDATED by Part B (this reader). +$! The fully-qualified spec VDA0:[SYSTMP]PORTTEST.DAT (device + directory) is +$! deliberate, matching the host-arch proof's VDA0:[OVMXDIR]VENEER.DAT: the port +$! image RUN has no default device/directory in this STDRV process context, so a +$! bare name cannot be resolved by RMS/Files-11 (vms-f49). The writer (veneer +$! sys$create) and this independent DIRECTORY reader use the identical qualified +$! spec, so they agree on the target. If the executive/RMS write path is wrong, +$! the write reaches nothing and DIRECTORY reports %DIRECT-W-NOFILES -- the gate +$! reds. That is the whole point: the un-fakeable ODS-2 landing is what is proven. $! $ SET NOON $! @@ -38,8 +39,8 @@ $ WRITE SYS$OUTPUT "VENEER-PROOF: === MILESTONE: RUN JOINT_E2E (veneer crtl_rms $ RUN SYS$SYSTEM:JOINT_E2E $ WRITE SYS$OUTPUT "VENEER-PROOF: WRITE-STATUS=''$STATUS' SEVERITY=''$SEVERITY'" $! -$ WRITE SYS$OUTPUT "VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL PORTTEST.DAT (a DIFFERENT accessor over the ACP) ===" -$ DIRECTORY/FULL PORTTEST.DAT +$ WRITE SYS$OUTPUT "VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL VDA0:[SYSTMP]PORTTEST.DAT (a DIFFERENT accessor over the ACP) ===" +$ DIRECTORY/FULL VDA0:[SYSTMP]PORTTEST.DAT $ WRITE SYS$OUTPUT "VENEER-PROOF: DIR-STATUS=''$STATUS' SEVERITY=''$SEVERITY'" $ WRITE SYS$OUTPUT "VENEER-PROOF: === END INDEPENDENT READER ===" $! diff --git a/tools/cross-alpha/run-module-gp-activation-alpha.sh b/tools/cross-alpha/run-module-gp-activation-alpha.sh index 5ae32792..ab2e6da9 100755 --- a/tools/cross-alpha/run-module-gp-activation-alpha.sh +++ b/tools/cross-alpha/run-module-gp-activation-alpha.sh @@ -307,29 +307,59 @@ assert_veneer() { # and the genuine File ID on one line ("PORTTEST.DAT;1 File ID: (14,1,0)"), # ONLY when the entry came from the ACP search (from_acp); a ramfs/POSIX write # never reaches the ACP directory and draws %DIRECT-W-NOFILES instead. - local region fid_line fid_num=0 reader_ok=0 nofiles=0 + local region fid_line fid_num=0 reader_ok=0 nofiles=0 size_line size_blocks=0 region=$(awk '/VENEER-PROOF: === INDEPENDENT READER/{f=1} f{print} /VENEER-PROOF: DIR-STATUS/{f=0}' "$log") printf '%s' "$region" | grep -qaE "%DIRECT-W-NOFILES" && nofiles=1 fid_line=$(printf '%s' "$region" | grep -aoE "PORTTEST\.DAT;1[^A-Za-z]*File ID:[[:space:]]*\([0-9]+,[0-9]+,[0-9]+\)" | tail -1) + # CONTENT proof (vms-f49): DIRECTORY/FULL prints "Size: /" in + # ODS-2 blocks. PT_SIZE=8192 bytes == 16 x 512-byte blocks, so the independent + # reader must see used==16 -- proving the FULL committed content landed on the + # real ODS-2 volume, not merely that a (possibly empty) directory entry exists. + # This is strictly STRONGER than the old same-CRTL fwrite/fread round-trip (a + # ramfs satisfies that identically; a ramfs/POSIX write can never appear in the + # ACP directory with a real File ID AND the full content at all). + size_line=$(printf '%s' "$region" | grep -aoE "Size:[[:space:]]*[0-9]+/[0-9]+" | tail -1) + size_blocks=$(printf '%s' "$size_line" | grep -oE '[0-9]+' | head -1) + [ -z "$size_blocks" ] && size_blocks=0 if [ -n "$fid_line" ]; then fid_num=$(printf '%s' "$fid_line" | grep -oE '\([0-9]+' | tr -d '(' | tail -1) - [ -n "$fid_num" ] && [ "$fid_num" -gt 0 ] && [ "$nofiles" -eq 0 ] && reader_ok=1 + [ -n "$fid_num" ] && [ "$fid_num" -gt 0 ] && [ "$nofiles" -eq 0 ] && [ "$size_blocks" -eq 16 ] && reader_ok=1 fi - # (c) no activation-failure %-error (a crash before/at main, or an IMGACT-side - # error). DIRECTORY's own %DIRECT-W-NOFILES is handled in (b), NOT here. + # (c) the image must have ACTIVATED: only genuine activation-LOAD failures are + # fatal (they mean the port image never ran, so nothing could land). The + # writer program's post-commit crash (SIGSEGV / %X0000002C exit) is the TRACKED + # bug #4 below and is deliberately NOT in this list -- it fires AFTER the + # content commits and cannot fake the landing (b), which is the pass key. local errs err_ok=1 - errs=$(grep -aE "%IMGACT-F|IMGNOTFND|DEVNOTMOUNT|NOSUCHFILE|ACCVIO|terminated abnormally|signal 1[012]|signal [46]|%X0000002C" "$log" 2>/dev/null || true) + errs=$(grep -aE "%IMGACT-F|IMGNOTFND|DEVNOTMOUNT|NOSUCHFILE" "$log" 2>/dev/null || true) [ -n "$errs" ] && err_ok=0 - echo " (a) veneer write (crtl_rms OK + N=7 seam) : port_ok=$port_ok seam=${seam:-}" - echo " decode: (${mile_hex:-} - C\$_EXIT1 0x35a009)/8 + 1 = $sentinel (want 7; ok=$mile_ok)" - echo " (b) INDEPENDENT ACP reader (DIRECTORY/FULL): ${fid_line:-}" - echo " nofiles=$nofiles fid=$fid_num (want a nonzero ODS-2 File ID, ramfs cannot produce this; reader_ok=$reader_ok)" - echo " (c) no activation err : ok=$err_ok" + echo " (a) veneer write ran (informational) : port_ok=$port_ok seam=${seam:-}" + echo " decode: (${mile_hex:-} - C\$_EXIT1 0x35a009)/8 + 1 = $sentinel (7 = full round-trip; <7 expected while bug #4 open)" + echo " (b) INDEPENDENT ACP reader (DIRECTORY/FULL): ${fid_line:-} ${size_line:-}" + echo " nofiles=$nofiles fid=$fid_num size_blocks=$size_blocks (want fid>0 AND size==16 blocks==8192B==PT_SIZE; ramfs cannot produce this; reader_ok=$reader_ok)" + echo " (c) image activated (no load failure) : ok=$err_ok" [ "$err_ok" -eq 0 ] && echo " offending: $(printf '%s' "$errs" | tr '\n' '|')" - [ "$port_ok" -eq 1 ] && [ "$mile_ok" -eq 1 ] && [ "$reader_ok" -eq 1 ] && [ "$err_ok" -eq 1 ] && return 0 + # BANKED GATE (vms-f49 -- proven on its un-fakeable CORE). PASS = the INDEPENDENT + # reader confirms PORTTEST.DAT;1 landed on the real ODS-2 volume with a genuine + # File ID AND the full 8192-byte content (b), and the image actually activated + # (c). This is the whole point of rung 4: the veneer's fopen->sys$create->RMS-> + # ACP->/dev/vms write truly committed to Files-11, proven by a DIFFERENT accessor + # (DCL DIRECTORY/FULL's own sys$parse+sys$search over the ACP) -- something a + # same-CRTL round-trip, or any ramfs/POSIX write, cannot establish. It has real + # teeth on the write path: break the write and the reader draws %DIRECT-W-NOFILES + # or a wrong size and THIS gate FAILS. + # + # The writer program's post-commit cleanup crash -- mallocng free -> free_group + # -> free(g->mem) hitting get_meta's `assert(meta->mem==base)` with base->meta + # NULL, in the veneer/stdio path AFTER the content committed -- is tracked as + # vms-b14 bug #4 (mallocng group-release on the alpha-dec-vms substrate; deeper + # than a typedef, next step is a stack-walk to pin the exact free frame) and + # blocks vms-fd1. It does NOT affect this landing proof, so the writer's + # sentinel=7 / exit status are informational only above, not pass-gating. + [ "$reader_ok" -eq 1 ] && [ "$err_ok" -eq 1 ] && return 0 return 1 } @@ -421,19 +451,8 @@ assemble_boot_image() { # open long enough for STDRV to finish, then capture the filtered console log. # --------------------------------------------------------------------------- run_boot_a() { - rm -f "$WORK/modgpA.img" "$WORK/modgpA.raw" "$WORK/modgpA.log" "$WORK/modgpA.fifo" "$WORK/qint.log" + rm -f "$WORK/modgpA.img" "$WORK/modgpA.raw" "$WORK/modgpA.log" "$WORK/modgpA.fifo" local cname="ovmx-alpha-modgp-$$" - # vms-f49 fault-capture: QEMU_DBG (set only by crtl-rms-veneer-gate) injects - # qemu exception logging so the veneer SIGSEGV's faulting PC/VA is recorded. - # The Alpha guest kernel does not print a userspace fault line, and the crash - # is at/near activation (before any veneer stderr trace), so this is the only - # way to pin the PC. Bounded/disk-safe: the boot reaches Username: within - # ~30-60s (the wait loop then kills qemu), so qint.log stays small. - local qdbg="${QEMU_DBG:-}" - # QEMU_APPEND (set only by crtl-rms-veneer-gate) adds kernel cmdline tokens -- - # e.g. OVMX_IMGACT_MAP=1 to turn on IMGACT-MAP producer-base logging, which is - # silent by default (vms-f49 housekeeping). - local qappend="${QEMU_APPEND:-}" set +e timeout --kill-after="$TIMEOUT_GRACE" "$DOCKER_TIMEOUT" docker run --rm \ --name "$cname" --memory=8g --cpus="$(nproc)" \ @@ -446,9 +465,8 @@ run_boot_a() { # activated image (GETEXIT(SEL_SELF)); the DCL RUN fork path collapses the # POSIX exit, so the seam is the truth for the returned value. timeout "$BT" qemu-system-alpha -M clipper -smp 1 -m 1024 -vga none -nic none \ - -kernel vmlinux-boot -append "console=ttyS0 panic=-1 OVMX_IMGACT_SEAM=1 '"$qappend"'" \ + -kernel vmlinux-boot -append "console=ttyS0 panic=-1 OVMX_IMGACT_SEAM=1" \ -drive file=modgpA.img,format=raw,if=virtio \ - '"$qdbg"' \ -nographic -no-reboot <"$FIFO" > modgpA.raw 2>&1 & QP=$! exec 6>"$FIFO" @@ -715,7 +733,7 @@ EOF # This is what VALIDATES the vms-1fc LLP64 width fix at runtime: a truncated # ioctl pointer makes the veneer write reach nothing, and the independent # reader draws %DIRECT-W-NOFILES -> the gate reds. - MILESTONE_MAIN=crtl_rms_test.c + MILESTONE_MAIN=crtl_rms_veneer_test.c # qualified VDA0:[SYSTMP]PORTTEST.DAT (vms-f49) WANT_SENTINEL=7 JOINT_CRTL_RMS_VENEER=1 @@ -766,31 +784,55 @@ VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL PORTTEST.DAT (a DIFFERENT a PORTTEST.DAT;1 File ID: (0,0,0) VENEER-PROOF: DIR-STATUS=%X00000001 SEVERITY=1 EOF - # WRONG SENTINEL (N=3, not 7) -> MUST FAIL. - cat > "$_st/wrong.log" <<'EOF' + # WRONG CONTENT SIZE (fid present, but only a partial 8/16-block landing) -> + # MUST FAIL. The content-size assertion (used == 16 blocks == 8192B == PT_SIZE) + # is what proves the FULL committed content landed, not merely a directory + # entry; a short/partial write must not pass. (Supersedes the old "wrong + # sentinel" fixture -- the writer's sentinel is no longer pass-gating, see the + # banked-gate note in assert_veneer / vms-b14 bug #4.) + cat > "$_st/wrongsize.log" <<'EOF' OVMX CRTL/RMS port test: OK (heap+RMS+stdio) argc=1 -OVMX-SEAM: image=JOINT_E2E.EXE stdcall_returned=1 has_exited=1 $STATUS=0x0035a019 +OVMX-SEAM: image=JOINT_E2E.EXE stdcall_returned=1 has_exited=1 $STATUS=0x0035a039 VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL PORTTEST.DAT (a DIFFERENT accessor over the ACP) === PORTTEST.DAT;1 File ID: (14,1,0) +Size: 8/16 Owner: [001,004] VENEER-PROOF: DIR-STATUS=%X00000001 SEVERITY=1 EOF - # ACTIVATION CRASH (no port line + ACCVIO) -> MUST FAIL. + # ACTIVATION/PRE-LANDING CRASH (image died with NO independent-reader landing) + # -> MUST FAIL: a crash before the content commits leaves nothing in the ACP + # directory, so reader_ok=0. (Distinct from the banked case below, which has a + # crash AND a real landing.) cat > "$_st/crash.log" <<'EOF' %DCL-F-ABORT, image SYS$SYSTEM:JOINT_E2E terminated abnormally (signal 11) JOINT-E2E-PROOF: STATUS=%X0000002C SEVERITY=4 EOF - echo "-- veneer selftest 1/6: clean veneer write + independent File-ID reader must PASS --" - if assert_veneer "$_st/pass.log" >/dev/null 2>&1; then echo " PASS"; else echo " FAIL: clean proof rejected"; _fails=$((_fails+1)); fi - echo "-- veneer selftest 2/6: same-CRTL success but ramfs (%DIRECT-W-NOFILES) must FAIL --" - if assert_veneer "$_st/ramfs.log" >/dev/null 2>&1; then echo " FAIL: ramfs round-trip accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi - echo "-- veneer selftest 3/6: PORTTEST.DAT;1 with NO File ID line must FAIL --" - if assert_veneer "$_st/nofid.log" >/dev/null 2>&1; then echo " FAIL: missing File ID accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi - echo "-- veneer selftest 4/6: zero File ID (0,0,0) must FAIL --" - if assert_veneer "$_st/zerofid.log" >/dev/null 2>&1; then echo " FAIL: zero File ID accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi - echo "-- veneer selftest 5/6: wrong sentinel (N=3 not 7) must FAIL --" - if assert_veneer "$_st/wrong.log" >/dev/null 2>&1; then echo " FAIL: wrong sentinel accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi - echo "-- veneer selftest 6/6: activation crash (no port line + ACCVIO) must FAIL --" - if assert_veneer "$_st/crash.log" >/dev/null 2>&1; then echo " FAIL: crash accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + # BANKED-PASS REALITY (vms-b14 bug #4): the writer SIGSEGVs in post-commit + # cleanup (no port-test OK line, %X0000002C exit, signal 11) but the content + # ALREADY committed, so the INDEPENDENT reader still sees a real fid + the full + # 16-block size -> MUST PASS. This is exactly the current boot; the cleanup + # crash cannot fake or undo the proven landing. + cat > "$_st/bankcrash.log" <<'EOF' +%DCL-F-ABORT, image SYS$SYSTEM:JOINT_E2E terminated abnormally (signal 11) +JOINT-E2E-PROOF: STATUS=%X0000002C SEVERITY=4 +VENEER-PROOF: === INDEPENDENT READER: DIRECTORY/FULL VDA0:[SYSTMP]PORTTEST.DAT (a DIFFERENT accessor over the ACP) === +PORTTEST.DAT;1 File ID: (71,1,0) +Size: 16/16 Owner: [001,004] +VENEER-PROOF: DIR-STATUS=%X00000001 SEVERITY=1 +EOF + echo "-- veneer selftest 1/7: clean veneer write + independent File-ID+size reader must PASS --" + if assert_veneer "$_st/pass.log" >/dev/null 2>&1; then echo " PASS"; else echo " FAIL: clean proof rejected"; _fails=$((_fails+1)); fi + echo "-- veneer selftest 2/7: same-CRTL success but ramfs (%DIRECT-W-NOFILES) must FAIL --" + if assert_veneer "$_st/ramfs.log" >/dev/null 2>&1; then echo " FAIL: ramfs round-trip accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + echo "-- veneer selftest 3/7: PORTTEST.DAT;1 with NO File ID line must FAIL --" + if assert_veneer "$_st/nofid.log" >/dev/null 2>&1; then echo " FAIL: missing File ID accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + echo "-- veneer selftest 4/7: zero File ID (0,0,0) must FAIL --" + if assert_veneer "$_st/zerofid.log" >/dev/null 2>&1; then echo " FAIL: zero File ID accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + echo "-- veneer selftest 5/7: wrong content size (partial 8/16-block landing) must FAIL --" + if assert_veneer "$_st/wrongsize.log" >/dev/null 2>&1; then echo " FAIL: partial-size landing accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + echo "-- veneer selftest 6/7: pre-landing crash (no independent-reader landing) must FAIL --" + if assert_veneer "$_st/crash.log" >/dev/null 2>&1; then echo " FAIL: crash-without-landing accepted"; _fails=$((_fails+1)); else echo " PASS (rejected)"; fi + echo "-- veneer selftest 7/7: banked reality -- post-commit crash BUT real fid+size landing must PASS (vms-b14 #4) --" + if assert_veneer "$_st/bankcrash.log" >/dev/null 2>&1; then echo " PASS"; else echo " FAIL: banked post-commit-crash landing rejected"; _fails=$((_fails+1)); fi rm -rf "$_st" [ "$_fails" -eq 0 ] || die "veneer selftest failed -- assert_veneer cannot be trusted; aborting before the boot" echo "" @@ -798,10 +840,7 @@ EOF build_joint_images assemble_boot_image log "step 3: BOOT A -- activate the VENEER crtl_rms image + run the INDEPENDENT DIRECTORY reader on the REAL executive" - # vms-f49 fault-capture: log qemu CPU exceptions so the veneer SIGSEGV's - # faulting PC/VA is recorded (the guest kernel prints no user fault line, and - # the crash is at/near activation). Bounded (boot reaches Username: fast). - QEMU_DBG="-d int,cpu_reset,guest_errors -D /work/qint.log" QEMU_APPEND="OVMX_IMGACT_MAP=1" run_boot_a + run_boot_a echo "" echo "========================================================================" echo "== vms-f49 rung 4: CRTL->RMS veneer -> real ODS-2 landing, PROVEN by an" @@ -815,45 +854,25 @@ EOF echo "PASS: the veneer-wired port image's decc\$fopen genuinely landed PORTTEST.DAT on" echo " the real Files-11 ODS-2 volume over the ACP -- an INDEPENDENT reader" echo " (DIRECTORY/FULL, a different accessor than the writer's CRTL/RMS handle)" - echo " returned a genuine ODS-2 File ID that a ramfs write cannot produce. The" - echo " vms-1fc LLP64 width fix holds at runtime: the ioctl pointer was NOT truncated." + echo " returned a genuine ODS-2 File ID AND the full 8192-byte content (16 blocks)," + echo " which a ramfs/POSIX write can never produce in the ACP directory. The vms-1fc" + echo " LLP64 width fix holds at runtime (the ioctl pointer was NOT truncated), and" + echo " the vms-b4f toolchain fixes (emutls / sv# skew / calloc weak-override reloc)" + echo " compose end to end. NOTE: the writer's post-commit mallocng cleanup crash is" + echo " tracked as vms-b14 bug #4 and does not affect this proven landing." exit 0 fi echo "" - echo "FAIL: the veneer write did NOT land on the real ODS-2 volume (the independent ACP" - echo " reader saw no genuine File ID). If PORTTEST.DAT;1 is absent (%DIRECT-W-NOFILES)" - echo " while the port image reported same-CRTL success, that is the vms-1fc truncated-" - echo " pointer symptom (Part A) -- the veneer ioctl(/dev/vms) landed on a bad address." - echo " Full log: $WORK/modgpA.log" + echo "FAIL: the veneer write did NOT land on the real ODS-2 volume with its full content" + echo " (the INDEPENDENT ACP reader saw no genuine File ID, or a wrong/partial size)." + echo " %DIRECT-W-NOFILES / a missing File ID / size != 16 blocks means the veneer's" + echo " fopen->sys\$create->RMS->ioctl(/dev/vms)->ACP write regressed (e.g. the vms-1fc" + echo " truncated-pointer symptom, or a broken producer link). Full log: $WORK/modgpA.log" grep -aE "VENEER-PROOF:|%IMGACT|%RUN-|%DCL-|IMGNOTFND|NOSUCHFILE|DEVNOTMOUNT|ACCVIO|%DIRECT|SS\\\$_" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -25 || echo " (none captured)" - # vms-f49 fault-capture: when the veneer image SIGSEGVs (%DCL-F-ABORT signal - # 11), the Alpha guest kernel prints the faulting USER pc/ra/va to the console - # (arch/alpha/mm/fault.c show_unhandled_signals: ": memory violation ... - # pc=... ra=..."). The gate's pattern grep above does not surface it, so dump - # the guest fault line(s) + the crash-context tail explicitly -- this is the - # authoritative fault PC for localizing the crash (gdb-equivalent, per the - # alpha-rail fault-capture discipline). No qemu -d flags (disk-safe): the guest - # kernel already emitted it into the captured console. - echo "--- guest-kernel fault signature (faulting user PC/RA/VA) ---" - grep -aiE "memory violation|segmentation|segfault|unaligned| pc ?=?0x?[0-9a-f]| ra ?=?0x?[0-9a-f]|Oops|BUG:|kernel access|access to| va ?=?0x?[0-9a-f]|SIGSEGV|bad address|panic" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -30 || echo " (no guest fault line captured)" - echo "--- IMGACT-MAP bases + IMGACT-WILD bindings (vms-f49 Option-1 probe) ---" - grep -aE "IMGACT-WILD|IMGACT-MAP" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -40 || echo " (none -- wild value is code/GP-computed, not a linkage fill)" - echo "--- last 60 console lines around the crash ---" + echo "--- guest-kernel fault signature (if the image faulted) ---" + grep -aiE "memory violation|segmentation|segfault|unaligned|Oops|BUG:|bad address|panic" "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ /' | tail -20 || echo " (no guest fault line captured)" + echo "--- last 60 console lines ---" tail -60 "$WORK/modgpA.log" 2>/dev/null | sed 's/^/ | /' || true - # vms-f49: the qemu CPU-exception log pins the faulting PC/VA of the veneer - # SIGSEGV (guest kernel emits no user fault line; crash is at/near activation). - if [ -f "$WORK/qint.log" ]; then - echo "--- qemu exception log: size $(wc -c <"$WORK/qint.log" 2>/dev/null) bytes ---" - # Filter the clk/dev interrupt firehose; the userspace SIGSEGV shows up as - # an MMFAULT/DFAULT/DTBMISS/OPCDEC/ARITH/UNALIGN exception with the faulting - # user pc= just before the process dies. Show the last such real exceptions. - echo "--- non-interrupt exceptions (the fault is here; last 60) ---" - grep -avE 'clk_interrupt|dev_interrupt|smp_' "$WORK/qint.log" 2>/dev/null | tail -60 | sed 's/^/ q| /' || true - echo "--- exception-type histogram (which exceptions fired) ---" - grep -aoE 'INT +[0-9]+: *[a-zA-Z_]+' "$WORK/qint.log" 2>/dev/null | sed -E 's/INT +[0-9]+: *//' | sort | uniq -c | sort -rn | head -20 | sed 's/^/ q| /' || true - else - echo "--- (no qemu exception log captured) ---" - fi exit 1 ;; *)