ci: let Hatari close TT ACSI image cleanly #305
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: qualification | |
| on: | |
| push: | |
| pull_request: | |
| workflow_dispatch: | |
| jobs: | |
| infrastructure: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Build atari-runtime image | |
| run: docker build -t atari-runtime:m2 -f Containerfile . | |
| - name: Runtime metadata | |
| run: docker run --rm atari-runtime:m2 tools/runtime-info.sh | |
| - name: Hatari CLI capabilities | |
| run: docker run --rm atari-runtime:m2 sh -c 'hatari --help 2>&1 | tee /tmp/hatari-help.txt; grep -Ei "auto|run|program|gemdos|harddrive" /tmp/hatari-help.txt || true' | |
| - name: Hatari + EmuTOS smoke | |
| run: docker run --rm atari-runtime:m2 tools/smoke.sh | |
| - name: Verify M2 helper | |
| run: docker run --rm atari-runtime:m2 sh -n tools/qualify-m2.sh | |
| m2-emulator: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| profile: [st, ste, tt] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Build atari-runtime image | |
| run: docker build -t atari-runtime:m2 -f Containerfile . | |
| - name: Install floppy image tools | |
| run: sudo apt-get update && sudo apt-get install -y dosfstools mtools | |
| - name: Download canonical atari-dev M2 artifact | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| mkdir -p artifacts | |
| curl --fail --location \ | |
| -H "Authorization: Bearer $GH_TOKEN" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -o /tmp/atari-dev-m2.zip \ | |
| https://api.github.com/repos/Ploos-AS/atari-dev/actions/artifacts/10600359653/zip | |
| unzip -q /tmp/atari-dev-m2.zip -d artifacts | |
| test -s artifacts/HELLO.TOS | |
| test -s artifacts/MINIMAL.PRG | |
| sha256sum artifacts/HELLO.TOS artifacts/MINIMAL.PRG | |
| - name: Prove EmuTOS reaches video boot | |
| run: | | |
| rm -f artifacts/xvfb-${{ matrix.profile }}.log artifacts/boot-hatari-${{ matrix.profile }}.log | |
| docker run --rm \ | |
| -v "$PWD/artifacts:/runtime/artifacts" atari-runtime:m2 \ | |
| sh -c 'set -eu; Xvfb :99 -screen 0 1024x768x24 >/tmp/xvfb.log 2>&1 & x=$!; export DISPLAY=:99; sleep 1; timeout --signal=TERM --kill-after=2s 8s hatari --machine "${{ matrix.profile }}" --memsize ${{ matrix.profile == 'tt' && '4' || '1' }} --tos /runtime/roms/emutos.img >/tmp/hatari.log 2>&1 || rc=$?; rc=${rc:-0}; cp /tmp/xvfb.log /runtime/artifacts/xvfb-${{ matrix.profile }}.log; cp /tmp/hatari.log /runtime/artifacts/boot-hatari-${{ matrix.profile }}.log; kill "$x" 2>/dev/null || true; wait "$x" 2>/dev/null || true; case "$rc" in 0|124|137) exit 0 ;; *) exit "$rc" ;; esac' | |
| cat artifacts/xvfb-${{ matrix.profile }}.log || true | |
| cat artifacts/boot-hatari-${{ matrix.profile }}.log || true | |
| test -e artifacts/boot-hatari-${{ matrix.profile }}.log | |
| if grep -Eqi 'fatal|cannot open.*tos|no tos|failed to.*tos' artifacts/boot-hatari-${{ matrix.profile }}.log; then | |
| echo "ERROR: Hatari reported a fatal TOS boot error" >&2 | |
| exit 1 | |
| fi | |
| printf 'EmuTOS boot window %s: PASS\n' "${{ matrix.profile }}" | |
| - name: Execute canonical probe from GEMDOS drive | |
| run: | | |
| rm -f artifacts/MINPASS.TXT | |
| test -s artifacts/MINIMAL.PRG | |
| set +e | |
| docker run --rm \ | |
| -v "$PWD/artifacts:/runtime/artifacts" atari-runtime:m2 \ | |
| sh -c 'set +e; Xvfb :99 -screen 0 1024x768x24 >/tmp/xvfb.log 2>&1 & x=$!; export DISPLAY=:99; sleep 1; timeout --signal=TERM --kill-after=2s 45s hatari --machine "${{ matrix.profile }}" --memsize ${{ matrix.profile == 'tt' && '4' || '1' }} --tos /runtime/roms/emutos.img --harddrive /runtime/artifacts --gemdos-drive C --auto MINIMAL.PRG --trace os_base,gemdos --trace-file /runtime/artifacts/hatari-boot-trace-${{ matrix.profile }}.log --log-level debug --log-file /runtime/artifacts/hatari-boot-debug-${{ matrix.profile }}.log --run-vbls 1500 >/runtime/artifacts/hatari-stdout-${{ matrix.profile }}.log 2>/runtime/artifacts/hatari-stderr-${{ matrix.profile }}.log; rc=$?; kill "$x" 2>/dev/null || true; wait "$x" 2>/dev/null || true; exit "$rc"' | |
| rc=$? | |
| set -e | |
| cat "artifacts/hatari-stderr-${{ matrix.profile }}.log" || true | |
| cat "artifacts/hatari-stdout-${{ matrix.profile }}.log" || true | |
| grep -Ei 'MINIMAL|PRG|Pexec|Fcreate|Fwrite|Fclose|GEMDOS|boot' "artifacts/hatari-boot-trace-${{ matrix.profile }}.log" 2>/dev/null | tail -n 300 || true | |
| if [ "$rc" -ne 0 ] && [ ! -s artifacts/MINPASS.TXT ]; then | |
| echo "ERROR: Hatari ended without guest marker (rc=$rc)" >&2 | |
| exit 1 | |
| fi | |
| test -s artifacts/MINPASS.TXT | |
| grep -F 'Ploos-AS atari-runtime minimal GEMDOS execution PASS' artifacts/MINPASS.TXT | |
| printf 'Canonical GEMDOS execution probe %s: PASS\n' "${{ matrix.profile }}" | |
| - name: Discover FreeMiNT TT snapshot payload | |
| if: matrix.profile == 'tt' | |
| run: | | |
| set -eux | |
| curl --fail --location --retry 3 https://atari.joska.no/snapshots/freemint/bootable/freemint-latest-aranym.zip -o /tmp/freemint-tt.zip | |
| unzip -l /tmp/freemint-tt.zip | tee artifacts/freemint-tt-snapshot-inventory.txt | |
| unzip -q /tmp/freemint-tt.zip -d artifacts/freemint-tt | |
| find artifacts/freemint-tt -type f \( -iname 'mint*.prg' -o -iname 'mint.cnf' -o -iname 'xaaes.km' \) -print | tee artifacts/freemint-tt-candidates.txt | |
| test -s artifacts/freemint-tt-candidates.txt | |
| - name: Build FreeMiNT 68030 kernel for TT | |
| if: matrix.profile == 'tt' | |
| run: | | |
| set -eux | |
| sudo apt-get update | |
| sudo apt-get install -y make bzip2 wget build-essential libc6-dev | |
| git clone --depth 1 https://github.com/freemint/freemint.git /tmp/freemint-src | |
| cd /tmp/freemint-src | |
| export CROSS_TOOL=m68k-atari-mint | |
| export PATH="/usr/${CROSS_TOOL}/bin:$PATH" | |
| SYSROOT_DIR=/tmp/mint-toolchain ./.scripts/install-freemint.sh binutils gcc mintbin mintlib libcmini | |
| compiler="$(find /tmp/mint-toolchain \( -type f -o -type l \) -name m68k-atari-mint-gcc -print -quit)" | |
| if [ -z "$compiler" ]; then | |
| echo "ERROR: m68k-atari-mint-gcc not found after toolchain install" >&2 | |
| find /tmp/mint-toolchain -maxdepth 4 \( -type f -o -type l \) -print | sort | tail -n 300 | |
| exit 1 | |
| fi | |
| toolbin="$(dirname "$compiler")" | |
| export PATH="$toolbin:$PATH" | |
| mint_include="$(find /tmp/mint-toolchain -type f -path '*/include/mint/mintbind.h' -printf '%h\n' | sed 's#/mint$##' | head -n1)" | |
| test -n "$mint_include" | |
| echo "MiNT toolchain compiler: $compiler" | |
| echo "MiNT include root: $mint_include" | |
| "$compiler" --version | |
| test -s "$mint_include/mint/mintbind.h" | |
| cd sys | |
| make 030 M68K_ATARI_MINT_CFLAGS="-isystem $mint_include" | |
| test -s .compile_030/mint030.prg | |
| cp .compile_030/mint030.prg "$GITHUB_WORKSPACE/artifacts/mint030.prg" | |
| file "$GITHUB_WORKSPACE/artifacts/mint030.prg" | |
| sha256sum "$GITHUB_WORKSPACE/artifacts/mint030.prg" | |
| { | |
| echo 'milestone=M4.3' | |
| echo 'profile=tt-freemint' | |
| echo 'emulator=Hatari' | |
| echo 'machine=tt' | |
| echo 'kernel=mint030.prg' | |
| echo 'kernel_build=PASS' | |
| } | tee "$GITHUB_WORKSPACE/artifacts/hatari-m4-3-tt-freemint-build.txt" | |
| - name: Boot FreeMiNT 68030 on Hatari TT | |
| if: matrix.profile == 'tt' | |
| run: | | |
| set -eux | |
| # Use a real FAT12 Atari disk image. Once FreeMiNT takes over, | |
| # Hatari GEMDOS host-directory emulation is no longer a valid | |
| # filesystem qualification path for the kernel. | |
| rm -f artifacts/tt-freemint-hd.img /tmp/tt-freemint-part.img | |
| ./tools/make-atari-hd-image.sh 16 artifacts/tt-freemint-hd.img PLOOSTT | |
| dd if=artifacts/tt-freemint-hd.img of=/tmp/tt-freemint-part.img bs=512 skip=1 status=none | |
| mmd -i /tmp/tt-freemint-part.img ::/AUTO | |
| mmd -i /tmp/tt-freemint-part.img ::/MINT | |
| mmd -i /tmp/tt-freemint-part.img ::/MINT/1-19-CUR | |
| mcopy -i /tmp/tt-freemint-part.img artifacts/mint030.prg ::/AUTO/MINT030.PRG | |
| cat > /tmp/mint.cnf <<'EOF' | |
| # Ploos-AS atari-runtime M4.3 minimal TT FreeMiNT qualification. | |
| # The EXEC line is intentionally guest-side and runs only after | |
| # the FreeMiNT kernel has mounted its own FAT filesystem. | |
| echo PLOOS-M4.3-BEFORE-EXEC | |
| exec u:/c/PLOOSPRG.TOS --ploos-probe | |
| echo PLOOS-M4.3-AFTER-EXEC | |
| EOF | |
| cat > /tmp/ploosprobe.S <<'EOF' | |
| .text | |
| .globl _start | |
| _start: | |
| pea msg_enter | |
| move.w #9,-(sp) | |
| trap #1 | |
| addq.l #6,sp | |
| clr.w -(sp) | |
| pea filename | |
| move.w #0x3c,-(sp) | |
| trap #1 | |
| addq.l #8,sp | |
| tst.l d0 | |
| bmi.s fail | |
| move.w d0,d2 | |
| pea msg_created | |
| move.w #9,-(sp) | |
| trap #1 | |
| addq.l #6,sp | |
| pea marker | |
| move.l #marker_len,-(sp) | |
| move.w d2,-(sp) | |
| move.w #0x40,-(sp) | |
| trap #1 | |
| lea 12(sp),sp | |
| cmp.l #marker_len,d0 | |
| bne.s fail | |
| pea msg_written | |
| move.w #9,-(sp) | |
| trap #1 | |
| addq.l #6,sp | |
| move.w d2,-(sp) | |
| move.w #0x3e,-(sp) | |
| trap #1 | |
| addq.l #4,sp | |
| tst.l d0 | |
| bmi.s fail | |
| /* FreeMiNT Sync(): flush guest filesystem state to media. */ | |
| move.w #0x0150,-(sp) | |
| trap #1 | |
| addq.l #2,sp | |
| /* FreeMiNT Shutdown(SHUT_NOPOWEROFF): orderly unmount. */ | |
| move.l #3,-(sp) | |
| move.w #0x0151,-(sp) | |
| trap #1 | |
| addq.l #6,sp | |
| clr.w -(sp) | |
| trap #1 | |
| fail: | |
| move.w #1,-(sp) | |
| move.w #0x4c,-(sp) | |
| trap #1 | |
| .data | |
| msg_enter: | |
| .asciz "PLOOS-PROBE-ENTER\\r\\n" | |
| msg_created: | |
| .asciz "PLOOS-PROBE-CREATED\\r\\n" | |
| msg_written: | |
| .asciz "PLOOS-PROBE-WROTE\\r\\n" | |
| filename: | |
| .asciz "u:/c/PLOOSPASS.TXT" | |
| marker: | |
| .ascii "Ploos-AS atari-runtime FreeMiNT Hatari TT execution PASS\\r\\n" | |
| .equ marker_len, .-marker | |
| EOF | |
| assembler="$(find /tmp/mint-toolchain \( -type f -o -type l \) -name m68k-atari-mint-as -print -quit)" | |
| linker="$(find /tmp/mint-toolchain \( -type f -o -type l \) -name m68k-atari-mint-ld -print -quit)" | |
| test -n "$assembler" | |
| test -n "$linker" | |
| "$assembler" -m68030 -o /tmp/ploosprobe.o /tmp/ploosprobe.S | |
| "$linker" -s -e _start -o /tmp/PLOOSPRG.TOS /tmp/ploosprobe.o | |
| test -s /tmp/PLOOSPRG.TOS | |
| file /tmp/PLOOSPRG.TOS | |
| mcopy -i /tmp/tt-freemint-part.img /tmp/mint.cnf ::/MINT/1-19-CUR/MINT.CNF | |
| mcopy -i /tmp/tt-freemint-part.img /tmp/PLOOSPRG.TOS ::/PLOOSPRG.TOS | |
| # Keep the libc-free probe as the FreeMiNT shell startup binary. | |
| mcopy -i /tmp/tt-freemint-part.img /tmp/PLOOSPRG.TOS ::/MINT/1-19-CUR/sh.tos | |
| mdir -i /tmp/tt-freemint-part.img -/ :: | tee artifacts/hatari-m4-3-tt-freemint-disk.txt | |
| dd if=/tmp/tt-freemint-part.img of=artifacts/tt-freemint-hd.img bs=512 seek=1 conv=notrunc status=none | |
| set +e | |
| docker run --rm \ | |
| -v "$PWD/artifacts:/runtime/artifacts" atari-runtime:m2 \ | |
| sh -c 'set +e; Xvfb :99 -screen 0 1024x768x24 >/tmp/xvfb.log 2>&1 & x=$!; export DISPLAY=:99; sleep 1; timeout --signal=TERM --kill-after=3s 90s hatari --machine tt --memsize 4 --tos /runtime/roms/emutos.img --acsi /runtime/artifacts/tt-freemint-hd.img --fastfdc yes --run-vbls 3600 --trace os_base,gemdos --trace-file /runtime/artifacts/hatari-m4-3-tt-freemint-trace.log --log-level debug --log-file /runtime/artifacts/hatari-m4-3-tt-freemint-debug.log >/runtime/artifacts/hatari-m4-3-tt-freemint-stdout.log 2>/runtime/artifacts/hatari-m4-3-tt-freemint-stderr.log; rc=$?; cp /tmp/xvfb.log /runtime/artifacts/hatari-m4-3-tt-freemint-xvfb.log; kill "$x" 2>/dev/null || true; wait "$x" 2>/dev/null || true; exit "$rc"' | |
| rc=$? | |
| set -e | |
| cat artifacts/hatari-m4-3-tt-freemint-stderr.log || true | |
| grep -Ei 'FreeMiNT|MiNT|PLOOS|panic|fatal|error' artifacts/hatari-m4-3-tt-freemint-{stdout,stderr,debug,trace}.log 2>/dev/null | tail -n 400 | tee artifacts/hatari-m4-3-tt-freemint-visible.log || true | |
| # The probe writes its evidence to the FAT16 hard disk (C:). | |
| # Partition 1 starts at LBA 1, so inspect that partition directly. | |
| sync artifacts/tt-freemint-hd.img || sync | |
| sleep 2 | |
| dd if=artifacts/tt-freemint-hd.img of=/tmp/tt-freemint-part.img bs=512 skip=1 status=none | |
| mdir -i /tmp/tt-freemint-part.img :: | tee artifacts/hatari-m4-3-tt-freemint-postboot-disk.txt | |
| rm -f /tmp/PLOOSPASS.TXT | |
| mcopy -i /tmp/tt-freemint-part.img ::/PLOOSPASS.TXT /tmp/PLOOSPASS.TXT | |
| test -s /tmp/PLOOSPASS.TXT | |
| tr -d '\r' < /tmp/PLOOSPASS.TXT | grep -Fxq 'Ploos-AS atari-runtime FreeMiNT Hatari TT execution PASS' | |
| cp /tmp/PLOOSPASS.TXT artifacts/hatari-m4-3-tt-freemint-PLOOSPASS.TXT | |
| grep -Fq 'This is FreeMiNT v1.19.0-ALPHA' artifacts/hatari-m4-3-tt-freemint-stdout.log | |
| { | |
| echo 'milestone=M4.3' | |
| echo 'profile=tt-freemint' | |
| echo 'emulator=Hatari' | |
| echo 'machine=tt' | |
| echo 'cpu=68030' | |
| echo 'boot_media=FAT16-ACSI' | |
| echo 'evidence_media=FAT16-ACSI' | |
| echo 'kernel=mint030.prg' | |
| echo 'kernel_build=PASS' | |
| echo 'kernel_boot=PASS' | |
| echo 'guest_exec=PASS' | |
| echo 'guest_marker=PASS' | |
| echo "hatari_exit=$rc" | |
| } | tee artifacts/hatari-m4-3-tt-freemint-result.txt | |
| - name: Verify Atari-side GEMDOS execution evidence | |
| run: | | |
| test -s artifacts/MINPASS.TXT | |
| grep -F 'Ploos-AS atari-runtime minimal GEMDOS execution PASS' artifacts/MINPASS.TXT | |
| file artifacts/MINIMAL.PRG |