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
58 changes: 58 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8031,6 +8031,64 @@ jobs:
- 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-crtl-rms-fileop (vms-3320, parent vms-b4f, blocks vms-fd1): the
# UN-FAKEABLE CRTL->RMS FILE-OP veneer gate -- extends alpha-crtl-rms-veneer
# from the stdio family to open/creat/unlink/remove/rename/opendir/readdir/
# closedir. The port image (crtl_rms3_test.c) creats FOPCRE.DAT, creats+unlinks
# FOPDEL.DAT, creats+renames FOPSRC.DAT->FOPDST.DAT via the VECTOR-SUBSTITUTED
# decc$* file-ops (bound by symbol-vector INDEX to the crtl_rms_stdio.c veneer
# -> sys$create/$erase/$rename over the ACP), then an INDEPENDENT reader (DCL
# DIRECTORY, a different accessor) asserts FOPCRE.DAT + FOPDST.DAT present with
# genuine ODS-2 File IDs and FOPDEL.DAT/FOPSRC.DAT gone -- something a ramfs/
# POSIX write can never produce in the ACP directory. Runs a 4-case can-fail
# selftest before the boot. Same alpha_activation PR trigger + toolchain images.
# -----------------------------------------------------------------------
alpha-crtl-rms-fileop:
name: "OVMX/Alpha CRTL->RMS file-op veneer gate — boots the veneer-wired crtl_rms3 image on the real /dev/vms executive; its decc$open/creat/unlink/rename/opendir/readdir/closedir reach the ODS-2 ACP, then an INDEPENDENT DIRECTORY reader asserts the created+renamed files landed with genuine File IDs and the deleted+renamed-away files are gone (vms-3320, blocks vms-fd1)"
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 file-op veneer gate — qemu-system-alpha boots the veneer-wired crtl_rms3 image on the real /dev/vms executive; its decc$open/creat/unlink/rename/opendir/readdir/closedir drive sys$create/$open/$erase/$rename/$parse/$search over the ODS-2 ACP, then an INDEPENDENT reader (DCL DIRECTORY, a different accessor than the writer's CRTL handle) asserts FOPCRE.DAT + FOPDST.DAT landed with genuine ODS-2 File IDs and FOPDEL.DAT/FOPSRC.DAT are gone; runs a 4-case can-fail selftest before the boot"
run: tools/cross-alpha/run-module-gp-activation-alpha.sh crtl-rms-fileop-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
17 changes: 17 additions & 0 deletions docs/design-gcc-port-surface-gaps-register.md
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,23 @@ PORT image's DECC$SHR (a build sub-project — the alpha-dec-vms port world has
`vms_kif`/RMS substrate yet; the `vms-47e` child, §3.1). Until that lands, the
alpha port image's own file writes are still musl-POSIX → Linux-Alpha VFS.

> **UPDATE (vms-3320, blocks vms-fd1):** the CRTL→RMS veneer is now extended
> **beyond the stdio family** to the eight file-ops the GCC-port driver leans on:
> `open`/`creat` (temp-file minting → `sys$create`/`sys$open`), `unlink`/`remove`
> (cleanup → `sys$erase`), `rename` (atomic output finalization → the new
> `sys$rename` RMS service → executive ACP `IO$_MODIFY!IO$M_MOVE`, vms-de7: a
> directory-entry re-link that KEEPS the File ID, NOT erase+create), and
> `opendir`/`readdir`/`closedir` (directory enumeration → `sys$parse`+`sys$search`
> + `rms_search_fid`). All eight are added to `src/vmsrms/crtl_rms_stdio.c` and
> **vector-substituted into the alpha DECC$SHR in their sorted sv# slots**
> (`mk_decc_shr.sh` ALPHA_CRTL_RMS_USE block, in-place — never tail-appended;
> sv# skew is the vms-b14/vms-f49 trap). Proven un-fakeably on the real executive
> by an INDEPENDENT ACP reader for each op (`tests/qemu/test_syssvc_crtl_rms_veneer.c`,
> 40/40 — incl. rename keeping the SAME File ID), and wired as the alpha activation
> gate `crtl-rms-fileop-gate` (`crtl_rms3_test.c` + an independent DIRECTORY reader).
> This closes the **PORT-CRTL binding** for the file-op family; the compiler driver's
> temp-file/cleanup/dir-enum now reach real RMS/ODS-2, not musl-POSIX.

> **rd-ID caveat (Rule 10):** this table's "rd item" column reads `vms-1b5`, but
> in rd `vms-1b5` is actually the *decc$feature* item; the RMS-beyond-stdio item
> is **`vms-2e72`**. Doc↔rd cross-wiring for the conductor to reconcile.
Expand Down
140 changes: 137 additions & 3 deletions tests/qemu/test_syssvc_crtl_rms_veneer.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <fcntl.h> /* vms-3320: O_* for ovmx_crtl_open */

#include "vms_kif.h"
#include "rms/rms.h"
Expand Down Expand Up @@ -218,12 +219,145 @@ int main(void)
}

/* ================================================================= *
* 5. Isolation — erase the file so the fixture is restored. *
* 5. FILE-OP VENEER (vms-3320): decc$creat/open/unlink/remove/rename/ *
* opendir/readdir/closedir over RMS, each proven by the SAME *
* INDEPENDENT ACP reader a ramfs cannot fake. *
* ================================================================= */
#define CREATNAME "CVENEER.DAT"
#define CREATSPEC DIRSPEC CREATNAME
#define RENSRC DIRSPEC "RENSRC.DAT"
#define RENDST DIRSPEC "RENDST.DAT"
#define DIRA DIRSPEC "ENUMA.DAT"
#define DIRB DIRSPEC "ENUMB.DAT"

/* --- 5.1 creat mints a real ODS-2 file the independent reader sees. --- */
erase_spec(CREATSPEC ";*");
int cfd = ovmx_crtl_creat(CREATSPEC, 0);
check(cfd >= OVMX_CRTL_FD_BASE,
"5.1a: ovmx_crtl_creat -> sys$create over the ACP, returns a veneer fd");
if (cfd >= 0) ovmx_crtl_fdclose(cfd);
{
uint16_t cfid = 0; char ctail[128]; uint32_t cend = 0;
int cn = search_one(CREATSPEC ";*", &cfid, ctail, sizeof(ctail), &cend);
check(cn == 1,
"5.1b: independent sys$search finds the creat-minted file "
"(ramfs cannot appear on the ACP directory)");
check(cfid != 0,
"5.1c: the creat file carries a genuine nonzero ODS-2 File ID");
check(strstr(ctail, ";1") != NULL,
"5.1d: creat minted version ;1 (a genuine ODS-2 create)");
printf(" [independent ACP reader] creat resultant='%s' fid=(%u,...)\n",
ctail, cfid);
}

/* --- 5.2 unlink removes it; the independent reader sees it GONE. --- */
check(ovmx_crtl_unlink(CREATSPEC ";*") == 0,
"5.2a: ovmx_crtl_unlink -> sys$erase NORMAL");
check(search_one(CREATSPEC ";*", NULL, NULL, 0, &endst) == 0,
"5.2b: independent sys$search finds the unlinked file GONE "
"(a real ODS-2 directory-entry removal)");

/* --- 5.3 open(O_CREAT) mints; remove() (ISO C) deletes; reader agrees. --- */
{
erase_spec(CREATSPEC ";*");
int ofd = ovmx_crtl_open(CREATSPEC, O_CREAT | O_WRONLY | O_TRUNC);
check(ofd >= OVMX_CRTL_FD_BASE,
"5.3a: ovmx_crtl_open(O_CREAT) -> sys$create, returns a veneer fd");
if (ofd >= 0) ovmx_crtl_fdclose(ofd);
uint16_t ofid = 0;
check(search_one(CREATSPEC ";*", &ofid, NULL, 0, &endst) == 1 && ofid != 0,
"5.3b: independent reader sees the open(O_CREAT) file with a File ID");
check(ovmx_crtl_remove(CREATSPEC ";*") == 0,
"5.3c: ovmx_crtl_remove -> sys$erase NORMAL");
check(search_one(CREATSPEC ";*", NULL, NULL, 0, &endst) == 0,
"5.3d: independent reader sees the removed file GONE");
}

/* --- 5.4 rename: the ATOMIC re-link keeps the SAME File ID (teeth). --- */
{
erase_spec(RENSRC ";*");
erase_spec(RENDST ";*");
/* Create the source through the proven stdio veneer, capture its FID. */
OVMX_CRTL_FILE *sf = ovmx_crtl_fopen(RENSRC, "w");
check(sf != NULL, "5.4a: create RENSRC.DAT (fopen->sys$create)");
if (sf) { ovmx_crtl_fwrite("RENAMEME", 1, 8, sf); ovmx_crtl_fclose(sf); }
uint16_t src_fid = 0;
check(search_one(RENSRC ";*", &src_fid, NULL, 0, &endst) == 1 && src_fid != 0,
"5.4b: independent reader sees RENSRC.DAT with File ID X");

check(ovmx_crtl_rename(RENSRC, RENDST) == 0,
"5.4c: ovmx_crtl_rename -> sys$rename (ACP MODIFY!M_MOVE) NORMAL");

check(search_one(RENSRC ";*", NULL, NULL, 0, &endst) == 0,
"5.4d: independent reader sees the OLD name RENSRC.DAT GONE");
uint16_t dst_fid = 0; char dtail[128];
int dn = search_one(RENDST ";*", &dst_fid, dtail, sizeof(dtail), &endst);
check(dn == 1,
"5.4e: independent reader sees the NEW name RENDST.DAT present");
check(dst_fid != 0 && dst_fid == src_fid,
"5.4f: RENDST.DAT carries the SAME File ID as RENSRC had -- proves "
"an ATOMIC directory-entry re-link, NOT erase+create (a new FID)");
printf(" [independent ACP reader] rename: RENSRC fid=(%u,...) -> "
"RENDST '%s' fid=(%u,...) SAME=%s\n",
src_fid, dtail, dst_fid, (src_fid == dst_fid) ? "YES" : "NO");
/* On-disk header confirms the moved file keeps its FID + allocation. */
struct rms_fileattr rattr; memset(&rattr, 0, sizeof rattr);
uint32_t rst = rms_file_attr(RENDST, &rattr);
check($VMS_STATUS_SUCCESS(rst) && rattr.fid_num == src_fid,
"5.4g: RENDST.DAT on-disk header File ID == the source's (two "
"independent readers agree the file kept its FID)");
erase_spec(RENDST ";*");
}

/* --- 5.5 opendir/readdir enumerate the REAL ODS-2 directory entries. --- */
{
erase_spec(DIRA ";*");
erase_spec(DIRB ";*");
OVMX_CRTL_FILE *fa = ovmx_crtl_fopen(DIRA, "w");
if (fa) ovmx_crtl_fclose(fa);
OVMX_CRTL_FILE *fb = ovmx_crtl_fopen(DIRB, "w");
if (fb) ovmx_crtl_fclose(fb);
check(fa != NULL && fb != NULL, "5.5a: create ENUMA.DAT + ENUMB.DAT");

OVMX_CRTL_DIR *dp = ovmx_crtl_opendir(DIRSPEC);
check(dp != NULL, "5.5b: ovmx_crtl_opendir(dir) -> sys$parse over the ACP");
int saw_a = 0, saw_b = 0, fid_a = 0, fid_b = 0, total = 0;
if (dp) {
struct ovmx_crtl_dirent *e;
while ((e = ovmx_crtl_readdir(dp)) != NULL) {
total++;
if (strstr(e->d_name, "ENUMA.DAT")) { saw_a = 1; fid_a = e->d_fileid; }
if (strstr(e->d_name, "ENUMB.DAT")) { saw_b = 1; fid_b = e->d_fileid; }
}
check(ovmx_crtl_closedir(dp) == 0,
"5.5c: ovmx_crtl_closedir -> rms_search_end (context released)");
}
check(saw_a && saw_b,
"5.5d: readdir enumerated BOTH real ODS-2 entries by name");
check(fid_a != 0 && fid_b != 0 && fid_a != fid_b,
"5.5e: each enumerated entry carries its genuine (distinct) File ID");
/* Cross-check against the independent single-file searches. */
uint16_t ia = 0, ib = 0;
search_one(DIRA ";*", &ia, NULL, 0, &endst);
search_one(DIRB ";*", &ib, NULL, 0, &endst);
check((uint16_t)fid_a == ia && (uint16_t)fid_b == ib,
"5.5f: readdir's File IDs match the independent sys$search File IDs "
"(same genuine ODS-2 directory, two readers agree)");
printf(" [independent ACP reader] readdir enumerated %d entries; "
"ENUMA fid=%d (search %u), ENUMB fid=%d (search %u)\n",
total, fid_a, ia, fid_b, ib);
erase_spec(DIRA ";*");
erase_spec(DIRB ";*");
}

/* ================================================================= *
* 6. Isolation — erase the stdio-veneer file so the fixture is *
* restored. *
* ================================================================= */
st = erase_spec(VSPEC ";*");
check($VMS_STATUS_SUCCESS(st), "5a: sys$erase VENEER.DAT (isolation)");
check($VMS_STATUS_SUCCESS(st), "6a: sys$erase VENEER.DAT (isolation)");
check(search_one(VSPEC ";*", NULL, NULL, 0, &endst) == 0,
"5b: a final search finds NONE (fixture restored)");
"6b: a final search finds NONE (fixture restored)");

free(buf);

Expand Down
5 changes: 5 additions & 0 deletions tools/cross-alpha-vms/joint-e2e/build-joint-image.sh
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ cp "$WORK/LINK.EXE" "$WORK/DECC\$SHR.EXE" "$WORK/libots/LIBOTS_SHR.EXE" "$OUT/"
# SYS$SHARE search-path set -- with no extra copy needed when the veneer path
# built it; a plain (non-veneer) run leaves $RMS empty and stages nothing new.
echo "== joint-e2e image built (genuine alpha path, vms-864) =="
# vms-3320: the FILE-OP veneer gate (JOINT_MAIN=crtl_rms3_test.c) drops a marker
# so build-alpha-bootimage.sh stages the FILE-OP independent-reader SYSTARTUP
# (DIRECTORY of the FOP*.DAT set) instead of the stdio VENEER one (which reads
# PORTTEST.DAT). Any other JOINT_MAIN leaves it absent -> unchanged behaviour.
[ "$JOINT_MAIN" = crtl_rms3_test.c ] && { : > "$OUT/FILEOP_PROOF"; echo "== FILEOP_PROOF marker staged (vms-3320 file-op veneer gate) =="; }
ls -la "$OUT/"
readelf -h "$OUT/joint_e2e.exe" | grep -E "Type|Machine|Entry"
readelf -SW "$OUT/joint_e2e.exe" | grep -E "vms\\\$xfer|vms\\\$imp|CODE|DATA" || true
Expand Down
Loading
Loading