diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 000000000..00fa31a15 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,251 @@ +# Copyright 2021, Proofcraft Pty Ltd +# Copyright 2026, UNSW +# +# SPDX-License-Identifier: BSD-2-Clause + +# Deploy default.xml to microkit-manifest after successful runs. + +name: Deploy + +on: + push: + # TEMP: remove + branches: [main, julia/ci, julia/ci-clean] + paths-ignore: + - '**.md' + + # allow manual trigger + workflow_dispatch: + + # allow explicit trigger from other repos when dependencies have changed + repository_dispatch: + types: [deps-update] + +jobs: + code: + name: Freeze Code + runs-on: ubuntu-latest + outputs: + xml: ${{ steps.repo.outputs.xml }} + steps: + - id: repo + uses: au-ts/seL4-ci-actions/repo-checkout@julia/microkit + with: + manifest_repo: au-ts/microkit-manifest + manifest_branch: main + manifest: main.xml + + # TODO: We want to add support for this but have yet to do so. + # sim: + # name: Simulation + # needs: code + # runs-on: ubuntu-latest + # strategy: + # matrix: + # march: [aarch64, x86_64, riscv64] + # compiler: [gcc] + # steps: + # - uses: au-ts/seL4-ci-actions/microkit-sim@julia/microkit + # with: + # xml: ${{ needs.code.outputs.xml }} + # march: ${{ matrix.march }} + # compiler: ${{ matrix.compiler }} + + sdk-build: + name: Build SDK (macOS, all targets) + needs: code + runs-on: [self-hosted, macos, ARM64] + outputs: + SDK_VERSION: ${{ steps.version.outputs.SDK_VERSION }} + steps: + - name: Clean build + run: | + rm -rf "$GITHUB_WORKSPACE" + mkdir -p "$GITHUB_WORKSPACE" + - name: Checkout code + uses: au-ts/seL4-ci-actions/repo-checkout@julia/microkit + with: + xml: ${{ needs.code.outputs.xml }} + # needed for reasons... + manifest_repo: au-ts/microkit-manifest + manifest_branch: main + manifest: main.xml + - name: Set version + id: version + run: ./ci/sdk_version.sh + working-directory: ./microkit/ + - name: Get Nix dependencies + run: nix develop -c bash -c 'echo Hello World' + working-directory: ./microkit/ + - name: Build SDK + # TODO: remove boards + run: nix develop --ignore-environment -c bash -c "python3 build_sdk.py --sel4=../seL4 --version ${{ env.SDK_VERSION }} --gcc-toolchain-prefix-x86_64 x86_64-elf --gcc-toolchain-prefix-riscv64 riscv64-none-elf --release-packaging" + working-directory: ./microkit/ + - name: Upload SDK (macos-aarch64) + uses: actions/upload-artifact@v7 + with: + name: microkit-sdk-${{ env.SDK_VERSION }}-macos-aarch64 + path: microkit/release/microkit-sdk-${{ env.SDK_VERSION }}-macos-aarch64.tar.gz + - name: Upload SDK (macos-x86-64) + uses: actions/upload-artifact@v7 + with: + name: microkit-sdk-${{ env.SDK_VERSION }}-macos-x86-64 + path: microkit/release/microkit-sdk-${{ env.SDK_VERSION }}-macos-x86-64.tar.gz + - name: Upload SDK (linux-aarch64) + uses: actions/upload-artifact@v7 + with: + name: microkit-sdk-${{ env.SDK_VERSION }}-linux-aarch64 + path: microkit/release/microkit-sdk-${{ env.SDK_VERSION }}-linux-aarch64.tar.gz + - name: Upload SDK (linux-x86-64) + uses: actions/upload-artifact@v7 + with: + name: microkit-sdk-${{ env.SDK_VERSION }}-linux-x86-64 + path: microkit/release/microkit-sdk-${{ env.SDK_VERSION }}-linux-x86-64.tar.gz + + # Not used for HW Run, just to confirm it builds on Linux outside of Nix. + sdk-build-linux: + name: Build SDK (Linux x86_64) + runs-on: ubuntu-24.04 + needs: code + steps: + - name: Checkout code + uses: au-ts/seL4-ci-actions/repo-checkout@julia/microkit + with: + xml: ${{ needs.code.outputs.xml }} + # needed for reasons... + manifest_repo: au-ts/microkit-manifest + manifest_branch: main + manifest: main.xml + - name: Set version + run: ./ci/sdk_version.sh + working-directory: ./microkit/ + - name: Install SDK dependencies + run: ./ci/install_ubuntu_deps.sh + working-directory: ./microkit/ + - name: Build SDK (x86-64) + run: ./pyenv/bin/python build_sdk.py --sel4=../seL4 --version ${{ env.SDK_VERSION }}-linux-x86-64 --tool-target-triple="x86_64-unknown-linux-musl" + working-directory: ./microkit/ + + the_matrix: + name: Matrix + needs: sdk-build + runs-on: ubuntu-latest + outputs: + gh_matrix: ${{ steps.matrix.outputs.gh_matrix }} + test_cases: ${{ steps.matrix.outputs.test_cases }} + steps: + - name: Checkout code + uses: au-ts/seL4-ci-actions/repo-checkout@julia/microkit + with: + xml: ${{ needs.code.outputs.xml }} + # needed for reasons... + manifest_repo: au-ts/microkit-manifest + manifest_branch: main + manifest: main.xml + - id: matrix + uses: au-ts/seL4-ci-actions/microkit-hw-matrix@julia/microkit + env: + # We don't actually care what this is set to, but for the files for + # each platform it expects this path to exist, so we set it up. + MICROKIT_SDK: /dummy-microkit-sdk-for-matrix + + hw-build: + name: HW Test Builds + if: ${{ github.repository_owner == 'au-ts' }} + runs-on: ubuntu-latest + # FIXME: Add simulation support + # needs: [sim, the_matrix, sdk-build] + needs: [the_matrix, sdk-build] + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.the_matrix.outputs.gh_matrix) }} + env: + SDK_VERSION: ${{ needs.sdk-build.outputs.SDK_VERSION }} + steps: + - name: Checkout code + uses: au-ts/seL4-ci-actions/repo-checkout@julia/microkit + with: + xml: ${{ needs.code.outputs.xml }} + # needed for reasons... + manifest_repo: au-ts/microkit-manifest + manifest_branch: main + manifest: main.xml + - name: Download microkit SDK + uses: actions/download-artifact@v8 + with: + name: microkit-sdk-${{ env.SDK_VERSION }}-linux-x86-64 + - name: Extract microkit SDK + run: | + tar xzf ./microkit-sdk-${{ env.SDK_VERSION }}-linux-x86-64.tar.gz + export "MICROKIT_SDK=$(realpath ./microkit-sdk-${{ env.SDK_VERSION }}/)" + echo "MICROKIT_SDK=${MICROKIT_SDK}" >> "${GITHUB_ENV}" + - name: Install build dependencies + run: ./ci/install_march_build_deps.sh ${{ matrix.march }} + working-directory: ./microkit/ + - name: Build + uses: au-ts/seL4-ci-actions/microkit-hw-build@julia/microkit + with: + board: ${{ matrix.board }} + index: $${{ strategy.job-index }} + env: + TEST_CASES: ${{ needs.the_matrix.outputs.test_cases }} + - name: Upload test case builds + uses: actions/upload-artifact@v7 + with: + name: loader-img-${{ matrix.board }} + path: '*.loader.img' + + hw-run: + name: HW Run + if: ${{ github.repository_owner == 'au-ts' }} + runs-on: ubuntu-latest + needs: [the_matrix, hw-build, sdk-build] + strategy: + fail-fast: false + matrix: ${{ fromJson(needs.the_matrix.outputs.gh_matrix) }} + # do not run concurrently with other workflows, but do run concurrently in the build matrix + concurrency: hw-run-${{ strategy.job-index }} + env: + SDK_VERSION: ${{ needs.sdk-build.outputs.SDK_VERSION }} + steps: + - name: Get machine queue + uses: actions/checkout@v6 + with: + repository: seL4/machine_queue + path: machine_queue + - name: Download test cases builds + uses: actions/download-artifact@v8 + with: + name: loader-img-${{ matrix.board }} + - name: Download microkit SDK + uses: actions/download-artifact@v8 + with: + name: microkit-sdk-${{ env.SDK_VERSION }}-linux-x86-64 + - name: Extract microkit SDK + run: | + tar xzf ./microkit-sdk-${{ env.SDK_VERSION }}-linux-x86-64.tar.gz + export "MICROKIT_SDK=$(realpath ./microkit-sdk-${{ env.SDK_VERSION }}/)" + echo "MICROKIT_SDK=${MICROKIT_SDK}" >> "${GITHUB_ENV}" + - name: Run + uses: au-ts/seL4-ci-actions/microkit-hw-run@julia/microkit + with: + board: ${{ matrix.board }} + index: $${{ strategy.job-index }} + env: + TEST_CASES: ${{ needs.the_matrix.outputs.test_cases }} + HW_SSH: ${{ secrets.HW_SSH }} + + deploy: + name: Deploy manifest + if: ${{ github.repository_owner == 'au-ts' }} + runs-on: ubuntu-24.04 + needs: [code, hw-run, sdk-build-linux] + steps: + - name: Deploy + uses: au-ts/seL4-ci-actions/manifest-deploy@julia/microkit + with: + xml: ${{ needs.code.outputs.xml }} + manifest_repo: au-ts/microkit-manifest + manifest_branch: main + env: + GH_SSH: ${{ secrets.CI_SSH }} diff --git a/.github/workflows/sdk.yaml b/.github/workflows/sdk.yaml index 72451d6d0..30610d008 100644 --- a/.github/workflows/sdk.yaml +++ b/.github/workflows/sdk.yaml @@ -45,36 +45,9 @@ jobs: ref: ${{ env.SEL4_VERSION }} path: seL4 - name: Install SDK dependencies - run: | - rustup install 1.94.0 - rustup default 1.94.0 - rustup target add x86_64-unknown-linux-musl - rustup component add rust-src --toolchain 1.94.0-x86_64-unknown-linux-gnu - rustup target add aarch64-unknown-none - rustup target add riscv64gc-unknown-none-elf - rustup target add x86_64-unknown-none - sudo apt update - sudo apt install software-properties-common - sudo add-apt-repository ppa:deadsnakes/ppa - sudo apt install \ - gcc-x86-64-linux-gnu \ - gcc-riscv64-unknown-elf \ - cmake pandoc device-tree-compiler ninja-build \ - texlive-latex-base texlive-latex-recommended \ - texlive-fonts-recommended texlive-fonts-extra \ - libxml2-utils \ - python3.12 python3-pip python3.12-venv \ - qemu-system-arm qemu-system-misc - python3.12 -m venv pyenv - ./pyenv/bin/pip install --upgrade pip setuptools wheel - ./pyenv/bin/pip install -r requirements.txt - - name: Install AArch64 GCC toolchain - run: | - wget -O aarch64-toolchain.tar.gz https://sel4-toolchains.s3.us-east-2.amazonaws.com/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf.tar.xz%3Frev%3D28d5199f6db34e5980aae1062e5a6703%26hash%3DF6F5604BC1A2BBAAEAC4F6E98D8DC35B - tar xf aarch64-toolchain.tar.gz - echo "$(pwd)/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf/bin" >> $GITHUB_PATH + run: ./ci/install_ubuntu_deps.sh - name: Set version - run: echo "SDK_VERSION=$(./ci/sdk_version.sh)" >> $GITHUB_ENV + run: ./ci/sdk_version.sh - name: Build SDK (x86-64) run: ./pyenv/bin/python build_sdk.py --sel4=seL4 --version ${{ env.SDK_VERSION }}-linux-x86-64 --tool-target-triple="x86_64-unknown-linux-musl" # The macOS run is slightly different to Linux since it also produces the @@ -98,26 +71,26 @@ jobs: - name: Get Nix dependencies run: nix develop -c bash -c 'echo Hello World' - name: Set version - run: echo "SDK_VERSION=$(./ci/sdk_version.sh)" >> $GITHUB_ENV + run: ./ci/sdk_version.sh - name: Build SDK run: nix develop --ignore-environment -c bash -c "python3 build_sdk.py --sel4=seL4 --version ${{ env.SDK_VERSION }} --gcc-toolchain-prefix-x86_64 x86_64-elf --gcc-toolchain-prefix-riscv64 riscv64-none-elf --release-packaging" - name: Upload SDK (macos-aarch64) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: microkit-sdk-${{ env.SDK_VERSION }}-macos-aarch64 path: release/microkit-sdk-${{ env.SDK_VERSION }}-macos-aarch64.tar.gz - name: Upload SDK (macos-x86-64) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: microkit-sdk-${{ env.SDK_VERSION }}-macos-x86-64 path: release/microkit-sdk-${{ env.SDK_VERSION }}-macos-x86-64.tar.gz - name: Upload SDK (linux-aarch64) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: microkit-sdk-${{ env.SDK_VERSION }}-linux-aarch64 path: release/microkit-sdk-${{ env.SDK_VERSION }}-linux-aarch64.tar.gz - name: Upload SDK (linux-x86-64) - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: microkit-sdk-${{ env.SDK_VERSION }}-linux-x86-64 path: release/microkit-sdk-${{ env.SDK_VERSION }}-linux-x86-64.tar.gz diff --git a/build_sdk.py b/build_sdk.py index c98143173..fa020f128 100644 --- a/build_sdk.py +++ b/build_sdk.py @@ -18,7 +18,7 @@ import shutil from pathlib import Path from dataclasses import dataclass -from sys import executable +from sys import executable, stderr from tarfile import open as tar_open, TarInfo import platform as host_platform from enum import IntEnum @@ -877,6 +877,20 @@ def build_initialiser( dest.chmod(0o744) +def github_actions_board_matrix( + matrix_file: Path, build_goals: list[tuple[BoardInfo, list[ConfigInfo]]] +) -> None: + + board_matrix = [ + {"board": board.name, "march": board.arch.to_str(), "config": config.name} + for (board, configs) in build_goals + for config in configs + ] + + with open(matrix_file, "w") as f: + json.dump(board_matrix, f) + + def main() -> None: parser = ArgumentParser() parser.add_argument("--sel4", type=Path, required=True) @@ -891,6 +905,7 @@ def main() -> None: parser.add_argument("--skip-docs", action="store_true", help="Docs will not be built") parser.add_argument("--skip-tar", action="store_true", help="SDK and source tarballs will not be built") parser.add_argument("--release-packaging", action="store_true", help="All SDKs for distribution will be produced") + parser.add_argument("--matrix", type=Path, help="Print out elaborated configs to a matrix for GitHub actions") # Read from the version file as unless someone has specified # a version, that is the source of truth with open("VERSION", "r") as f: @@ -939,6 +954,10 @@ def main() -> None: build_goals.append((board, elaborated_configs)) + if args.matrix is not None: + github_actions_board_matrix(args.matrix, build_goals) + return + sel4_dir = args.sel4.expanduser() if not sel4_dir.exists(): raise Exception(f"sel4_dir: {sel4_dir} does not exist") diff --git a/ci/install_march_build_deps.sh b/ci/install_march_build_deps.sh new file mode 100755 index 000000000..375283501 --- /dev/null +++ b/ci/install_march_build_deps.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash + +# Copyright 2026, UNSW +# SPDX-License-Identifier: BSD-2-Clause + +set -e + +if [ -z "${NO_APT_UPDATE}" ]; then + sudo apt-get update +fi + +march="$1" +shift + +do_aarch64() { + wget -O aarch64-toolchain.tar.gz https://sel4-toolchains.s3.us-east-2.amazonaws.com/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf.tar.xz%3Frev%3D28d5199f6db34e5980aae1062e5a6703%26hash%3DF6F5604BC1A2BBAAEAC4F6E98D8DC35B + tar xf aarch64-toolchain.tar.gz + echo "$(pwd)/arm-gnu-toolchain-12.2.rel1-x86_64-aarch64-none-elf/bin" >> $GITHUB_PATH +} + +do_riscv64() { + sudo apt-get install -qq gcc-riscv64-unknown-elf +} + +do_x86_64() { + sudo apt-get install -qq gcc-x86-64-linux-gnu +} + +case "${march}" in + aarch64) + do_aarch64 + ;; + + riscv64) + do_riscv64 + ;; + + x86_64) + do_x86_64 + ;; + + *) + echo "Unknown or empty march value '${march}'" >&2 + exit 1 + ;; +esac diff --git a/ci/install_ubuntu_deps.sh b/ci/install_ubuntu_deps.sh new file mode 100755 index 000000000..1727f6fb9 --- /dev/null +++ b/ci/install_ubuntu_deps.sh @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +# Copyright 2026, UNSW +# SPDX-License-Identifier: BSD-2-Clause + +set -e + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) + +rustup install 1.94.0 +rustup default 1.94.0 +rustup target add x86_64-unknown-linux-musl +rustup component add rust-src --toolchain 1.94.0-x86_64-unknown-linux-gnu +rustup target add aarch64-unknown-none +rustup target add riscv64gc-unknown-none-elf +rustup target add x86_64-unknown-none + +sudo apt-get update + +NO_APT_UPDATE=1 $SCRIPT_DIR/install_march_build_deps.sh aarch64 +NO_APT_UPDATE=1 $SCRIPT_DIR/install_march_build_deps.sh riscv64 +NO_APT_UPDATE=1 $SCRIPT_DIR/install_march_build_deps.sh x86_64 + +# sel4-only dependencies +sudo apt-get install -qq software-properties-common +sudo add-apt-repository ppa:deadsnakes/ppa +sudo apt-get install -qq \ + cmake pandoc device-tree-compiler ninja-build \ + texlive-latex-base texlive-latex-recommended \ + texlive-fonts-recommended texlive-fonts-extra \ + libxml2-utils \ + python3.12 python3-pip python3.12-venv \ + qemu-system-arm qemu-system-misc + +python3.12 -m venv pyenv +./pyenv/bin/pip install --upgrade pip setuptools wheel +./pyenv/bin/pip install -r requirements.txt diff --git a/ci/local_run.sh b/ci/local_run.sh new file mode 100755 index 000000000..54dd6da37 --- /dev/null +++ b/ci/local_run.sh @@ -0,0 +1,99 @@ +#!/usr/bin/env bash + +# Copyright 2026, UNSW +# SPDX-License-Identifier: BSD-2-Clause + +set -e + +SCRIPT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) + +if [ "$#" -ne 3 ]; then + echo >&2 "Usage: $0 " + exit 1 +fi + +export MICROKIT_SDK=$(readlink -f "$1") +export CI_ACTIONS=$(readlink -f "$2") +export GITHUB_WORKSPACE=$(readlink -f "$3") + +run_ci_actions_steps() { + export INPUT_ACTION_NAME="$1" + action_script="${2:-steps.sh}" + + export SCRIPTS="${CI_ACTIONS}/scripts" + export PATH="${SCRIPTS}:${PATH}" + + action_dir="${CI_ACTIONS}/${INPUT_ACTION_NAME}" + + "${action_dir}/${action_script}" +} + +# secrets +export HW_SSH=$(cat ~/.ssh/id_ed25519) +# pseudo-sandbox +export HOME="${GITHUB_WORKSPACE}" + +# used for the job key in machine queue +export GITHUB_REPOSITORY="microkit" +export GITHUB_WORKFLOW="locally" +export GITHUB_RUN_ID="local" +export GITHUB_JOB="local" + +# Make sudo a no-op +sudo_tmpdir=$(mktemp -d) +printf '#!/usr/bin/env bash\necho >&2 ignoring sudo "$@"\n' > "${sudo_tmpdir}/sudo" +chmod +x "${sudo_tmpdir}/sudo" +export PATH="${sudo_tmpdir}:${PATH}" + +export GITHUB_OUTPUT=$(mktemp) +export GITHUB_ENV=$(mktemp) + +mkdir -p "${GITHUB_WORKSPACE}" + +# Always create a log file in the build folder. +# use -i so that tee always exits after this script +mkdir -p "${GITHUB_WORKSPACE}/logs" +LOGFILE="${GITHUB_WORKSPACE}/logs/local_run_$(date '+%Y-%m-%d-%H').txt" +echo 2>&1 "Emitting logs to ${LOGFILE}" +exec > >(tee -i "${LOGFILE}") 2>&1 + +unset PYTHONPATH +python3 -m venv "${GITHUB_WORKSPACE}/venv" +. "${GITHUB_WORKSPACE}/venv/bin/activate" + +# don't create __pycache__ folders +export PYTHONDONTWRITEBYTECODE=1 + +# Pretend microkit is installed here. +mkdir -p "${GITHUB_WORKSPACE}/microkit" +ln -sf "${SCRIPT_DIR}/../build_sdk.py" "${GITHUB_WORKSPACE}/microkit/build_sdk.py" +ln -sf "${SCRIPT_DIR}/../VERSION" "${GITHUB_WORKSPACE}/microkit/VERSION" + +cd "${GITHUB_WORKSPACE}" + +run_ci_actions_steps "microkit-hw-matrix" + +export TEST_CASES=$(cat "${GITHUB_OUTPUT}" | grep "test_cases" | cut -d "=" -f 2) + +run_ci_actions_steps "microkit-hw-build" + +# Note: This rarely works, because non-interactive bash assumes wait-for-coordinated +# exit and most of our python scripts do not follow this protocol. +trap_handler() { + really_die() { + # Implement Wait-and-Cooperative-Exit protocol + trap - SIGINT + kill -s SIGINT $$ + } + + echo >&2 "Handling SIGINT signal" + trap 'really_die' SIGINT + + run_ci_actions_steps "microkit-hw-run" "post-steps.sh" + + really_die +} + +trap 'trap_handler' SIGINT + +run_ci_actions_steps "microkit-hw-run" diff --git a/ci/sdk_version.sh b/ci/sdk_version.sh index 9c500cf14..0c6475771 100755 --- a/ci/sdk_version.sh +++ b/ci/sdk_version.sh @@ -6,13 +6,24 @@ set -e VERSION=`cat VERSION` -LATEST_TAG=`git describe --tags --abbrev=0` -NUM_COMMITS=`git rev-list --count $LATEST_TAG..HEAD` + HEAD=`git rev-parse --short HEAD` -if [[ $NUM_COMMITS -eq 0 ]]; -then +if ! LATEST_TAG=`git describe --tags --abbrev=0`; then + VERSION="$VERSION.unknown+$HEAD" +elif ! NUM_COMMITS=`git rev-list --count $LATEST_TAG..HEAD`; then + VERSION="$VERSION.unknown+$HEAD" +elif [ $NUM_COMMITS -eq 0 ]; then echo "$VERSION" else - echo "$VERSION.$NUM_COMMITS+$HEAD" + VERSION="$VERSION.$NUM_COMMITS+$HEAD" +fi + +echo "SDK Version is '${VERSION}'" + +if [ -n "${GITHUB_ENV}" ]; then + echo "SDK_VERSION=${VERSION}" >> "${GITHUB_ENV}" +fi +if [ -n "${GITHUB_OUTPUT}" ]; then + echo "SDK_VERSION=${VERSION}" >> "${GITHUB_OUTPUT}" fi