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/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) 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/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-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 new file mode 100644 index 00000000..126cc787 --- /dev/null +++ b/tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM @@ -0,0 +1,47 @@ +$! 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 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 +$! +$ 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 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 ===" +$! +$ EXIT diff --git a/tools/cross-alpha/build-alpha-bootimage.sh b/tools/cross-alpha/build-alpha-bootimage.sh index 6cc33ace..1f14ebe4 100755 --- a/tools/cross-alpha/build-alpha-bootimage.sh +++ b/tools/cross-alpha/build-alpha-bootimage.sh @@ -176,9 +176,33 @@ 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 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. (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 + # 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 + 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" + 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 +247,16 @@ 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 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). + # 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; } 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..ab2e6da9 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,106 @@ 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 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 ] && [ "$size_blocks" -eq 16 ] && reader_ok=1 + fi + + # (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" "$log" 2>/dev/null || true) + [ -n "$errs" ] && err_ok=0 + + 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' '|')" + + # 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 +} + # --------------------------------------------------------------------------- # 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 +381,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 +409,25 @@ 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 + # 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 } # --------------------------------------------------------------------------- @@ -589,7 +720,162 @@ 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_veneer_test.c # qualified VDA0:[SYSTMP]PORTTEST.DAT (vms-f49) + 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 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=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/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 + # 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 "" + + 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 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 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)" + 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 + 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