Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
82 changes: 82 additions & 0 deletions src/imgact/imgact.c
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,76 @@ 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 <image>+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);
Expand Down Expand Up @@ -1574,6 +1644,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; }

Expand Down Expand Up @@ -1751,6 +1822,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);
Expand Down Expand Up @@ -2835,6 +2915,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++)
Expand Down
27 changes: 24 additions & 3 deletions tools/cross-alpha-vms/joint-e2e/build-joint-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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" \
Expand Down
46 changes: 46 additions & 0 deletions tools/cross-alpha/SYSTARTUP_VMS_VENEER_PROOF.COM
Original file line number Diff line number Diff line change
@@ -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
41 changes: 37 additions & 4 deletions tools/cross-alpha/build-alpha-bootimage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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"
Expand Down
Loading
Loading