Eclipse ThreadX — Foundation-hosted Linux x86-64 GitHub Actions runner
## The request
Eclipse ThreadX needs a **Foundation-hosted Linux x86-64 GitHub Actions runner** with the Armv8-R AEM Fixed Virtual Platform installed, so that the model-execution lanes of two repositories can run.
Please note that it is possible we might need to add runners for additional Arm FVPs or equivalent packages from other silicon vendors in the future.
One runner serves both, which is why this is one request rather than two:
| Repository | What is not executed today |
|------------|----------------------------|
| `eclipse-threadx/zonex` | 24 registered tests across 14 registration sites. Built on every pull request, executed never |
| `eclipse-threadx/threadx` | The Cortex-R52 port's model suite — `r52-fvp-<image>` under CTest, with a `check-r52-fvp` target. No workflow in that repository references the FVP at all |
In GitHub's terminology any runner that is not GitHub-hosted is a "self-hosted" runner, so this is a request for Foundation-operated self-hosted capacity rather than for the project to stand up a machine of its own. The reasons for that preference are below, and they are the substance of the request rather than a courtesy.
## What is missing, and why it matters
`zx_fvp.yml` builds every Cortex-R52 image and then executes none of them, because the model is not present on a GitHub-hosted runner. The workflow takes a download location from an `FVP_AEMV8R_URL` repository variable; that variable is unset, so the lane emits a warning, writes `### ZoneX FVP execution: SKIPPED` to the job summary, and exits zero. The build lanes still gate every pull request, and the skip is loud rather than silent.
The effect is nonetheless that **CI proves ZoneX compiles under four toolchains and that the repository checks pass. It does not prove that a single ZoneX image runs.**
Both are cases where the claim being made is behavioural and has no static equivalent. ZoneX is a partitioning hypervisor: a partition is denied its neighbour's memory, a window ends on time whether the partition agrees or not, a guest's clock advances only inside its own window. The ThreadX Cortex-R52 work includes a PMSAv8-R Stage-1 module port that isolates User-mode modules from the kernel and from each other. Isolation and timing are behavioural by definition — which is why the suite is built so that each image judges itself and reports a verdict, and why 14 registration sites produce 24 tests, several of them builds that **must fail** on the specific check they were written to violate. A compile exercises none of it.
Today that evidence comes from runs on a contributor's own workstation and development board, recorded by hand before anything lands. That is what the project's published measurements rest on, in both repositories. It does not scale to contributors who have neither the model nor the board, and it means a behavioural regression is caught by a person rather than by CI.
## Why GitHub-hosted runners cannot close it
Arm distributes the AEM FVP free of charge, but behind a click-through licence and with no stable unauthenticated download URL. Making the current `FVP_AEMV8R_URL` route work therefore means either publishing a redistribution of Arm's archive somewhere a runner can reach, or pointing at a URL that will rot.
The first is a redistribution question for the Foundation rather than a technical one for the project, and the project would rather ask it explicitly than answer it by assumption. The second reintroduces the fragility the variable was added to avoid.
**A model pre-installed on a persistent runner needs no URL at all**, which removes the redistribution question from the critical path instead of answering it. If the Foundation would rather answer the redistribution question — host a mirror the project may point at — that is equally welcome and probably simpler; the two are alternatives and either closes the gap.
## Why the project would rather not self-host
Two reasons, and the second is the one that should decide it.
**It would be a single point of failure attached to one person.** A machine maintained by the contributor who happens to own a development board does not survive that contributor moving on, and the project's CI would quietly stop meaning anything at the moment nobody noticed.
**The isolation model is a security responsibility the project is not equipped to carry.** GitHub advises against self-hosted runners on public repositories, and the advice applies here in full: a pull request from a fork can change the workflow it runs, so a naive self-hosted runner would let any contributor execute arbitrary code on the host. Every pull request this repository has had, including the one introducing the component, came from a fork. That is a standing operational duty — patching, isolation, credential hygiene, incident response — and it belongs with infrastructure that is somebody's job.
The project is willing to accept constraints that make this cheap to operate. In particular, it is happy for **execution to run only on `push` to `dev` and `main`**, so that the runner never executes code that has not already been reviewed and merged. That forgoes the pre-merge signal on a fork's pull request and keeps it for everything that lands, and it removes the fork-execution problem rather than mitigating it. If the Foundation's runners are ephemeral and per-job, pre-merge execution becomes discussable; the project is not asking for it up front.
`pull_request_target` will not be used to reach this. It runs the base repository's workflow with write-scoped credentials against a fork's code, which is worse than the problem.
## What the runner needs
| | |
|--|--|
| OS | Linux x86-64. ZoneX is Linux-only by decision, and the model ships for this host only |
| Model | [Armv8-R AEM FVP](https://support.arm.com/tools-and-software/fixed-virtual-platforms/arm-architecture-fvps), `FVP_BaseR_AEMv8R`. Verified against Fast Models 11.32+19 |
| Licence server | **None.** The AEM FVP needs no licence daemon. The workflow runs `--version` and then the binary |
| Disk | \~150 MB for the model. Another 1–2 GB if the Arm GNU Toolchain and Arm Toolchain for Embedded are cached on the runner rather than fetched per run; fetching per run is acceptable |
| CPU and memory | Modest. A functional simulator on one core; 2 vCPU and 4 GB is ample |
| Wall-clock | 4 to 8 minutes for the full 24-test suite. Measured three times in one week at 425 s, 229 s and 236 s on a workstation |
| Network | Outbound to GitHub only. The suite reaches nothing else, and the images have no networking |
| Secrets | None. The runner needs no credentials for anything |
| Guest images | The ZoneX workflow checks out ThreadX itself; no additional provisioning |
| Build options | The ThreadX lane must configure with `TX_R52_BUILD_FVP_MODULE_EXAMPLE=ON`; the module manager example defaults to `OFF` and is otherwise neither built nor tested |
## What the project will do on its side
- Add the runner label to the execution jobs in both repositories and constrain their triggers to whatever the Foundation's isolation model requires.
- Keep the existing skip path. A contributor without the model, and a fork without access to the runner, must still get the build lanes rather than a red cross they cannot act on.
- Record the isolation model in the workflow next to the trigger it constrains, so that the next person to widen a trigger sees why it is narrow.
- Update `CONTRIBUTING.md`, whose continuous-integration section currently describes five workflows all running on GitHub-hosted runners.
## Acceptance criteria
- The execution lane runs the images and reports each one's self-declared verdict.
- The negative builds still fail the suite when they **pass**, which is the property that makes the positive results evidence.
- A fork pull request with no runner access still gets the four build lanes and the repository checks.
## Priority
- [ ] Urgent
- [x] High
- [ ] Medium
- [ ] Low
## Severity
- [ ] Blocker
- [ ] Major
- [x] Normal
- [ ] Low
I appreciate your support.
issue