diff --git a/.github/workflows/zx_fvp.yml b/.github/workflows/zx_fvp.yml index e27e89c..4517417 100644 --- a/.github/workflows/zx_fvp.yml +++ b/.github/workflows/zx_fvp.yml @@ -129,26 +129,18 @@ jobs: # Matches gcc_check.yml so the two share one toolchain cache entry. GCC_VERSION: 14.3.rel1 - # Where the Armv8-R AEM FVP comes from. + # The Armv8-R AEM FVP, from Arm's unauthenticated download permalink. + # Only the _Linux_x86.tar.gz name resolves; the _Linux64.tgz name of + # older releases returns 404. The archive holds Arm's installer, which + # refuses to run until its EULA is accepted, so the install step accepts + # it. The model is fetched from Arm on every cache miss and never + # re-hosted. # - # Arm distributes it free of charge but behind a click-through licence, - # with no stable unauthenticated download URL that can be hard-coded -- - # the permalink forms under developer.arm.com/-/cdn-downloads all 404 for - # this model. So the location is a repository variable rather than a - # literal, and a maintainer sets it once to somewhere the runner can - # reach: an Eclipse-hosted mirror, a release asset, or Arm's own URL if a - # durable one ever appears. - # - # Set FVP_AEMV8R_URL to a .tgz/.tar.gz of the model, and optionally - # FVP_AEMV8R_SHA256 to its checksum. With the checksum set the download - # is verified; without it the run says so rather than pretending. - # - # When the variable is unset the build lanes still run and still gate the - # pull request -- only execution is skipped, loudly, in the log and in the - # job summary. A silent green here would recreate the exact hole this - # workflow exists to close. - FVP_URL: ${{ vars.FVP_AEMV8R_URL }} - FVP_SHA256: ${{ vars.FVP_AEMV8R_SHA256 }} + # Pinned with its checksum so that a change of model is a reviewed diff. + # Keep the version in step with the find_program hint in + # examples/fvp_baser_aemv8r/CMakeLists.txt. + FVP_URL: https://developer.arm.com/-/cdn-downloads/permalink/FVPs-Architecture/FM-11.32/FVP_Base_AEMv8R_11.32_19_Linux_x86.tar.gz + FVP_SHA256: e6d046946529db86129ee6d8e7a2d5c3667d6c4c98365ad815586db8bca06613 steps: - name: Check out the repository @@ -205,36 +197,32 @@ jobs: sudo apt-get install -y --no-install-recommends ninja-build fi - # Keyed on the URL's own hash rather than a version string, so pointing the - # variable at a different model fetches it instead of serving the old one - # from cache. A raw URL may contain characters a cache key cannot. + # Keyed on the archive's checksum, which changes exactly when the model + # does. - name: Cache the Armv8-R AEM FVP id: cache-fvp - if: env.FVP_URL != '' uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: fvp - key: fvp-aemv8r-${{ hashFiles('.github/workflows/zx_fvp.yml') }}-${{ env.FVP_SHA256 || 'nosum' }} + key: fvp-aemv8r-${{ env.FVP_SHA256 }} - name: Install the Armv8-R AEM FVP - if: env.FVP_URL != '' && steps.cache-fvp.outputs.cache-hit != 'true' + if: steps.cache-fvp.outputs.cache-hit != 'true' run: | set -eu - mkdir -p fvp && cd fvp - curl -fsSL -o fvp.tgz "$FVP_URL" - if [ -n "${FVP_SHA256:-}" ]; then - echo "$FVP_SHA256 fvp.tgz" | sha256sum -c - - else - echo "::warning::FVP_AEMV8R_SHA256 is not set; the download was not verified." - fi - tar xf fvp.tgz - rm -f fvp.tgz + mkdir -p fvp-download + curl -fsSL --retry 3 -o fvp-download/fvp.tar.gz "$FVP_URL" + echo "$FVP_SHA256 fvp-download/fvp.tar.gz" | sha256sum -c - + tar xzf fvp-download/fvp.tar.gz -C fvp-download + sh fvp-download/FVP_Base_AEMv8R_*_Linux_x86.sh \ + --i-agree-to-the-contained-eula --no-interactive \ + -d "$GITHUB_WORKSPACE/fvp" + rm -rf fvp-download # The model links against libatomic. Everything else it needs is already - # on the runner image, and its own libscxframework/libsystemc ship inside - # the tarball. Guarded for the same reason the ninja step is. + # on the runner image, and its own libscxframework/libsystemc ship with + # the model. Guarded for the same reason the ninja step is. - name: Ensure the FVP's runtime dependencies are present - if: env.FVP_URL != '' run: | set -eu if ldconfig -p | grep -q 'libatomic\.so\.1'; then @@ -252,33 +240,19 @@ jobs: # ZX_FVP_BASER_AEMV8R, which means -DZX_FVP_BASER_AEMV8R= overrides # it with no change to the CMake files. # - # "present", not a bare "did the variable exist", so that a URL which - # downloads something that is not the model fails here rather than silently - # skipping every test later. + # A missing binary fails here, rather than leaving CMake without a model + # and CTest with no tests to run. - name: Locate the FVP id: fvp run: | set -eu - if [ -z "${FVP_URL:-}" ]; then - echo "present=false" >>"$GITHUB_OUTPUT" - echo "::warning::FVP_AEMV8R_URL is not set for this repository, so the ZoneX images were built but NOT executed. Set the repository variable to enable the execution lanes." - { - echo "### ZoneX FVP execution: SKIPPED" - echo "" - echo "\`FVP_AEMV8R_URL\` is not set, so this run built the images but executed none of them." - echo "Set the repository variable (Settings -> Secrets and variables -> Actions -> Variables)" - echo "to a download URL for the Armv8-R AEM FVP to turn the execution lanes on." - } >>"$GITHUB_STEP_SUMMARY" - exit 0 - fi binary="$(find fvp -type f -name FVP_BaseR_AEMv8R -perm -u+x | head -1)" if [ -z "$binary" ]; then - echo "FVP_AEMV8R_URL was set, but no FVP_BaseR_AEMv8R binary was found in the archive." >&2 + echo "::error::The FVP install produced no FVP_BaseR_AEMv8R binary." find fvp -maxdepth 3 -type d | sed 's/^/ /' >&2 exit 1 fi binary="$(cd "$(dirname "$binary")" && pwd)/$(basename "$binary")" - echo "present=true" >>"$GITHUB_OUTPUT" echo "binary=$binary" >>"$GITHUB_OUTPUT" "$binary" --version @@ -288,21 +262,15 @@ jobs: export PATH="$GITHUB_WORKSPACE/toolchain/arm-gnu-toolchain-${GCC_VERSION}-x86_64-arm-none-eabi/bin:$PATH" arm-none-eabi-gcc --version | head -1 - fvp_present='${{ steps.fvp.outputs.present }}' fvp_binary='${{ steps.fvp.outputs.binary }}' - fvp_arg="" - if [ "$fvp_present" = "true" ]; then - fvp_arg="-DZX_FVP_BASER_AEMV8R=$fvp_binary" - fi - cmake -S . -B build/fvp -G Ninja \ -DCMAKE_TOOLCHAIN_FILE=cmake/cortex_r52.cmake \ -DCMAKE_COMPILE_WARNING_AS_ERROR=ON \ -DZX_BUILD_FVP_EXAMPLE=ON \ -DZX_BUILD_S32Z280_EXAMPLE=OFF \ -DZX_THREADX_SOURCE_DIR="$GITHUB_WORKSPACE/threadx" \ - $fvp_arg + -DZX_FVP_BASER_AEMV8R="$fvp_binary" cmake --build build/fvp @@ -380,9 +348,6 @@ jobs: # shellcheck disable=SC2086 cmake --build build/fvp --target $images - if [ "$fvp_present" != "true" ]; then - echo "Built, not executed (no FVP configured)." - exit 0 - fi - - ctest --test-dir build/fvp --output-on-failure + # --no-tests=error, because ctest reports success when it finds + # nothing to run. + ctest --test-dir build/fvp --output-on-failure --no-tests=error diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index edffb60..d0e47fa 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -143,7 +143,7 @@ Five GitHub Actions workflows. **Every one triggers on `pull_request` against `d | `clang_check.yml` | The same sources with Arm Toolchain for Embedded. GNU `as` accepts non-canonical assembly forms that LLVM's assembler rejects, and ZoneX is going to be substantially assembly. | | `zx_fvp.yml` | Builds the Cortex-R52 images and **executes** them on the Armv8-R AEM FVP, judging each by its self-reported result. There is no static check for "the partition still runs". | -Arm distributes the Armv8-R AEM FVP free of charge but behind a click-through licence with no stable unauthenticated URL, so `zx_fvp.yml` takes the download location from the `FVP_AEMV8R_URL` repository variable (with an optional `FVP_AEMV8R_SHA256`). When it is unset the build lanes still run and still gate the pull request; only execution is skipped, and it says so in the log and in the job summary rather than passing quietly. +`zx_fvp.yml` downloads the Armv8-R AEM FVP from Arm's public permalink, verifies it against a SHA-256 pinned in the workflow, and installs it with Arm's installer, so every run executes the images. A missing model fails the job. Toolchain versions are pinned explicitly, so a bump is a reviewable commit. Third-party actions are pinned to a commit SHA rather than a tag, and `.github/dependabot.yml` keeps those pins moving — a SHA pin without Dependabot freezes CI on whatever was current the day it was written.