summaryrefslogtreecommitdiff
path: root/.github/workflows
diff options
context:
space:
mode:
authorFrédéric Desbiens <[email protected]>2026-10-23 13:06:05 -0400
committerGitHub <[email protected]>2026-10-23 13:06:05 -0400
commit4c2179186c5348175bbce481cfafbc3d13f54a61 (patch)
treeece1b62db161d3aaf6b64dd67896beea5f2024d0 /.github/workflows
parent3a77bc385c6cac82c71e1c36d6817e0860d12526 (diff)
Added a QEMU module execution harness for the Cortex-M3 and M4 ports (#821)dev
No Cortex-M module port ran in CI. gcc_check compiles each port's module manager sources and links nothing that loads a module, and the host tests under test/tx/module_manager compile a few portable sources against stubs. A module's start-up, its kernel calls through the supervisor call, the MPU programming on context switches and the fault path that terminates a misbehaving module were exercised only on the Cortex-R52 FVP. test/tx/cmake/module_qemu is a stand-alone CMake project, like test/tx/cmake/riscv, that builds the kernel and Module Manager with a module port's headers, builds test modules position-independent with the port's module linker script, embeds their raw images in manager images, and registers each image with CTest. A Python runner starts it on QEMU's MPS2 board for the core, mps2-an385 for cortex_m3 and mps2-an386 for cortex_m4 built for its FPU with the hard-float ABI, and judges the result line the image prints over semihosting and the exit status it sets. Three images per port: a protected module loaded, started, exercising queues, semaphores, a worker thread and the timer, stopped and unloaded twice with its memory returned; the same module faulting on a read of kernel memory, reported to the fault notification with its module, thread and address and terminated, then stopped and unloaded; and the module built privileged and unprotected, whose identical read succeeds. The fault image is also the check that QEMU's MPU enforces at all. The new module_qemu workflow runs both ports on changes to common/, common_modules/, the two module ports and the harness, installing QEMU from the Ubuntu archive through the bounded apt helpers in scripts/tx_ci_common.sh. Both ports pass 3/3 on QEMU 8.2.2 with Arm GNU 14.3.rel1, using the workflow's commands, with zero compiler warnings; configure, build and run take 9 seconds for both. The AI disclosure check passes. The workflow itself has not run on GitHub yet. Assisted-by: Claude Code (Opus 5.5) <[email protected]>
Diffstat (limited to '.github/workflows')
-rw-r--r--.github/workflows/module_qemu.yml151
1 files changed, 151 insertions, 0 deletions
diff --git a/.github/workflows/module_qemu.yml b/.github/workflows/module_qemu.yml
new file mode 100644
index 00000000..7cc62709
--- /dev/null
+++ b/.github/workflows/module_qemu.yml
@@ -0,0 +1,151 @@
+name: module_qemu
+
+# Copyright (c) 2026 Eclipse ThreadX contributors
+# SPDX-License-Identifier: MIT
+# Portions of this file were generated with AI assistance.
+#
+# Builds the module execution harness in test/tx/cmake/module_qemu for each
+# Cortex-M module port it covers and EXECUTES every image on QEMU's MPS2
+# board for that core, asserting each image's self-reported result.
+#
+# Why this exists: until this workflow landed, no Cortex-M module port ran in
+# CI. gcc_check compiles the module manager sources once per port and links
+# nothing that loads a module; the host tests under test/tx/module_manager
+# compile a handful of portable module manager sources against stubs. A
+# module's start-up, its kernel calls through the supervisor call, the MPU
+# programming on every context switch and the fault path that terminates a
+# misbehaving module are only exercised by executing them, and r52_fvp does
+# that for the Cortex-R52 alone.
+#
+# What it covers, per port:
+#
+# - cortex_m3 on mps2-an385 and cortex_m4 on mps2-an386, the latter built
+# for its FPU with the hard-float ABI;
+# - a protected module loaded, started, exercising the kernel, stopped and
+# unloaded twice, with its memory given back;
+# - a protected module faulting on a read of kernel memory, reported to the
+# application and terminated -- which is also the proof that QEMU's MPU is
+# enforcing at all;
+# - the same module built privileged and unprotected, whose identical read
+# succeeds.
+#
+# QEMU comes from the Ubuntu archive. The images report through semihosting
+# and end the simulation themselves, so a hang shows up as the runner's
+# timeout rather than as a pass.
+
+on:
+ # push as well as pull_request, for the reason gcc_check.yml states at
+ # length: dev needs its own baseline so a bad squash-merge is caught then
+ # rather than by whoever opens the next pull request.
+ push:
+ branches: [ master, dev ]
+ paths:
+ - ".github/workflows/module_qemu.yml"
+ - "common/**"
+ - "common_modules/**"
+ - "ports_module/cortex_m3/**"
+ - "ports_module/cortex_m4/**"
+ - "test/tx/cmake/module_qemu/**"
+ - "scripts/tx_ci_common.sh"
+ pull_request:
+ branches: [ master, dev ]
+ # Duplicated rather than shared through a YAML anchor, as in r52_fvp.yml.
+ # **Edit both.**
+ paths:
+ - ".github/workflows/module_qemu.yml"
+ - "common/**"
+ - "common_modules/**"
+ - "ports_module/cortex_m3/**"
+ - "ports_module/cortex_m4/**"
+ - "test/tx/cmake/module_qemu/**"
+ - "scripts/tx_ci_common.sh"
+
+permissions:
+ contents: read
+
+jobs:
+ module_qemu:
+ runs-on: ubuntu-24.04
+ timeout-minutes: 30
+
+ env:
+ # Pinned deliberately and shared with gcc_check.yml, ci_cortex_m.yml and
+ # r52_fvp.yml through one cache entry; change them together.
+ GCC_VERSION: 14.3.rel1
+
+ steps:
+ - name: Check out the repository
+ uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
+
+ # Path and key match gcc_check.yml's AArch32 entry exactly, so the
+ # workflows share one cache entry.
+ - name: Cache the AArch32 Arm GNU toolchain
+ id: cache-arm32
+ uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
+ with:
+ path: toolchain
+ key: arm-gnu-toolchain-${{ env.GCC_VERSION }}-x86_64-arm-none-eabi
+
+ # The checksum suffix is .sha256asc and not .sha256; see gcc_check.yml.
+ - name: Install the AArch32 Arm GNU toolchain
+ if: steps.cache-arm32.outputs.cache-hit != 'true'
+ run: |
+ set -eu
+ base="https://developer.arm.com/-/media/Files/downloads/gnu/${GCC_VERSION}/binrel"
+ archive="arm-gnu-toolchain-${GCC_VERSION}-x86_64-arm-none-eabi.tar.xz"
+ mkdir -p toolchain && cd toolchain
+ curl -fsSLO "$base/$archive"
+ curl -fsSLO "$base/$archive.sha256asc"
+ sha256sum -c "$archive.sha256asc"
+ tar xf "$archive"
+ rm -f "$archive"
+
+ # Through the bounded, retried apt helpers in tx_ci_common.sh, for the
+ # reasons that file records: on this runner pool a bare apt call can stall
+ # for hours. Ninja is installed only if the image stopped shipping it.
+ - name: Install QEMU
+ run: |
+ set -eu
+ . scripts/tx_ci_common.sh
+ packages="qemu-system-arm"
+ command -v ninja >/dev/null 2>&1 || packages="$packages ninja-build"
+ retry sudo "${TIMEOUT[@]}" apt-get "${APT_OPTIONS[@]}" update || true
+ # shellcheck disable=SC2086
+ retry sudo "${TIMEOUT[@]}" apt-get "${APT_OPTIONS[@]}" install -y --no-install-recommends $packages
+ qemu-system-arm --version | head -1
+
+ - name: Build and run the module harness
+ run: |
+ set -eu
+ export PATH="$GITHUB_WORKSPACE/toolchain/arm-gnu-toolchain-${GCC_VERSION}-x86_64-arm-none-eabi/bin:$PATH"
+ arm-none-eabi-gcc --version | head -1
+
+ status=0
+ for port in cortex_m3 cortex_m4; do
+ build="build/module_qemu_$port"
+ echo ""
+ echo "=============================================================="
+ echo "== $port"
+ echo "=============================================================="
+
+ if ! cmake -S test/tx/cmake/module_qemu -B "$build" -G Ninja \
+ -DCMAKE_TOOLCHAIN_FILE="$PWD/test/tx/cmake/module_qemu/arm-none-eabi-qemu.cmake" \
+ -DMODULE_QEMU_PORT="$port"; then
+ echo "::error::$port: CMake configure failed"
+ status=1
+ continue
+ fi
+ if ! cmake --build "$build"; then
+ echo "::error::$port: the images did not build"
+ status=1
+ continue
+ fi
+ # --no-tests=error: the tests are registered only when QEMU and
+ # Python are found, and ctest's default would pass on none.
+ if ! ctest --test-dir "$build" --output-on-failure --no-tests=error; then
+ echo "::error::$port: one or more images failed on QEMU, or no tests were registered"
+ status=1
+ fi
+ done
+
+ exit $status