Hardware CI for Eclipse ThreadX on RISC-V
Boot ThreadX tests on real RISC-V boards, automatically, with the Cloud-V KernelCI/LAVA lab.
Akif Ejaz
Engineer @ 10xEngineers | Cloud-V developer | CM @ Eclipse ThreadX
Banana Pi F3
SpacemiT K1 — 8× RV64GC. The first ThreadX target board in the lab.
WHY NOW
ThreadX runs on RISC-V. CI does not see it.
2
RISC-V ports
risc-v32 and risc-v64; GNU, Clang, IAR
98
regression tests
build as bare-metal RISC-V programs
5
example targets
QEMU virt, CVA6, Core-V MCU, E906, BPI-F3
0
boards in CI
all RISC-V testing stops at emulation
What exists today on the working fork
The gap
No ThreadX code runs on real RISC-V silicon in CI. Real interrupt timing, real UART, and real SoC behavior stay untested until a person tests them by hand.
2
WHO WE ARE
Cloud-V: free RISC-V hardware for developers
Boards in the farm
VisionFive 1 & 2
Banana Pi F3
Milk-V Jupiter
Milk-V Pioneer
Milk-V Megrez
Scaleway EM-RV1
Users include
One board farm, four access paths: SSH, GitHub CI, GitLab CI, KernelCI.
3
THE SERVICE
The LAVA lab: boot-level testing on real boards
Available to ThreadX :
banana-pi-f3
riscv-virt-qemu
This flow runs in production today
1
Submit
lavacli -i cloudv jobs submit job.yaml
2
Schedule
The master queues the job on a healthy board.
3
Deploy
The worker downloads the images over HTTPS.
4
Boot
Power cycle, bootloader, kernel: each step is scripted.
5
Report
Live serial log and pass/fail results in the web UI.
4
INSIDE THE LAB
Every boot step is scripted. No manual steps.
LAVA master
kernelci-1.cloud-v.co
Scheduler, web UI, results database
Worker
An x86 host next to the boards. It runs the dispatcher.
Serial console
USB serial, shared through ser2net as telnet. The lab captures all boot output.
Power control
An Arduino with a relay PDU. Each job can switch the board on, off, or reset it.
File serving
TFTP and NFS servers on the worker. U-Boot downloads the test image from them.
BPI-F3
Health checks
A scheduled Linux boot proves each board healthy. An infrastructure fault never looks like a ThreadX fault.
Per-job bootloader
The BPI-F3 first-stage loader accepts U-Boot over UART on each reset. A job can also supply its own bootloader.
Full logs
The lab stores every action, command, and serial line with the job. You can debug a red run without board access.
5
THE OTHER HALF
ThreadX already has the hard parts
In the tree today (working fork)
Proven by hand on the Banana Pi F3
The exact manual commands:
=> tftpboot ${loadaddr} kernel.elf
=> bootelf ${loadaddr}
The only missing piece: automation between GitHub Actions and the board. That is what we are proposing.
6
THE PROPOSAL
One automated loop from pull request to silicon
GITHUB (THREADX REPO)
CLOUD-V LAB
1
Merge or nightly trigger
push to master, cron, or manual
2
Build test ELFs
GNU toolchain, rv64 regression set
3
Publish artifacts
ELF files at a public HTTPS URL
4
Submit the LAVA job
lavacli with an API token
5
Board runs each ELF
power cycle, U-Boot, tftpboot, bootelf
6
Parse serial output
a monitor matches the pass and fail markers
7
Report back
the workflow polls, converts to JUnit, sets the check
✓
green check
7
FITTING THE CI BUDGET
Right-sized tiers: fast PRs, deep nightlies
Every pull request
QEMU on the GitHub runner
Full RISC-V regression in emulation. Enable the job that already exists. No board time, no queue.
minutes
Every merge to master
Smoke set on the Banana Pi F3
About 5 ELF files, one per kernel object family. This catches hardware breakage on the day it lands.
10 to 25 min
Every night
Full suite on the board
All 98 tests, one boot each. The board queue serializes the runs. The lab retries each failure once.
2 to 8 h
9
HOW A TEST RUNS
Anatomy of one hardware test job
1. Deploy
The worker downloads the test ELF from the artifact URL and stages it for TFTP.
deploy:
to: tftp
kernel:
url: https://<artifacts>/
threadx_mutex_basic_test.elf
2. Boot
LAVA power-cycles the board and types the same commands a developer types.
boot:
method: u-boot
commands:
- tftpboot 0x00200000 {KERNEL}
- bootelf 0x00200000
3. Test
A monitor watches the serial console and turns marker lines into test results.
monitors:
- start: "ThreadX Validation"
end: "Testing Complete"
pattern: TX_TEST_RESULT:
(?P<test_case_id>\S+)
(?P<result>PASS|FAIL)
One small ThreadX change makes this work
On QEMU, ctest reads an exit code. A board has no exit code. It only has serial output. So the test BSP prints one line per run, for example TX_TEST_RESULT: threadx_mutex_basic_test PASS. LAVA turns that line into a test result.
8
SCOPE OF CHANGE
Small, contained changes on both sides
ThreadX repository
Cloud-V lab
10
ROLLOUT
Six checkpoints, each one testable
0
M0: Access
Account, token, and artifact host are ready.
1
M1: QEMU loop
A workflow run submits a LAVA QEMU job. The check goes green.
2
M2: First silicon
One regression ELF boots on the BPI-F3 with no manual steps.
3
M3: Results land
JUnit from the lab appears in the workflow. A forced failure turns the check red.
4
M4: Steady state
Smoke on merge and full nightly run for one week. We record the failure rate.
5
M5: Upstream
The workflow and templates merge into eclipse-threadx/threadx. The lab adds boards.
This sequence removes risk early
11
GUARDRAILS
Safe by design
✓
Fork PRs never touch hardware
Hardware jobs run on merge and nightly only. Fork PRs get no secrets and no board access. Code reaches silicon after review, not before.
✓
Credentials stay contained
A dedicated threadx-ci lab account. Its token lives only in GitHub environment secrets. One click revokes it.
✓
Infrastructure faults stay visible
Scheduled Linux health checks prove the board, power, serial, and network before any ThreadX job. A red ThreadX run points to ThreadX, not to cables.
✓
Flaky runs are contained
The workflow resubmits a failed job once. Two identical failures fail the check. The QEMU suite uses the same repeat policy today.
What the community gains: boots on real silicon back every RISC-V claim. Every PR shows the result in its checks.
12
DISCUSSION
What I ask from this community
1
Feedback on the design
Focus areas: the test tiers and the marker-line approach.
2
Approval to pilot
M0 to M4 run on the working fork. Nothing changes upstream yet.
3
Review when it lands
Ports, harness, and workflow arrive as normal PRs after the pilot.
First three actions after a yes
Pointers
Lab server
kernelci-1.cloud-v.co
Partner docs
10x-engineers.github.io/riscv-ci-partners
Lab internals
github.com/alitariq4589/lava-webserver-riscv
ThreadX work
github.com/akifejaz/threadx (dev)
Get access
cloud-v.co/contactus
Thank you. Questions are welcome.
13