First RTEMS boot¶
This walkthrough takes you from zero to a real RTEMS hello-world running on the emulator, using the RCC 1.3.2 SPARC cross-toolchain. By the end you will have run an RTEMS image, read its UART console output, and recognised what a clean RTEMS boot looks like.
flowchart LR
A[RTEMS source<br/>main.c] -->|sparc-gaisler-rtems5-gcc| B[hello.elf<br/>SPARC BE ET_EXEC]
B -->|optional: mkprom2| C[hello.rom<br/>PROM image]
B -->|--image .elf| D[tero-emu]
C -->|--image .rom| D
D -->|APBUART0 → stdout| E[Console output]
Prerequisites¶
- A working build of Tero (see Installation).
- The RCC 1.3.2 toolchain installed under
/opt/rcc-1.3.2-gcc/(the path the repo's build scripts assume). RCC 1.3.2 ships RTEMS 5.x.
No cross-toolchain? Use the pre-built image
The repository ships a pre-built hello-world.elf at
tests/guest-programs/rtems/hello-world/hello-world.elf. You can run
that directly without RCC; you only need the toolchain to rebuild it
or to compile your own guests.
1. Build or obtain the hello-world image¶
The repository includes the pre-built binary above. To rebuild from
source (requires sparc-gaisler-rtems5-gcc on PATH):
# From the repository root:
cmake --build build --target sparc_test_binaries
# The cross-compiled ELFs end up under the build directory.
You can also supply your own RCC toolchain and link script to produce a
compatible ELF — just place it at
tests/guest-programs/rtems/hello-world/hello-world.elf for the
integration tests to find it. For a full from-scratch walkthrough
(source, compile flags, and the optional mkprom2 PROM image) see the
Hello World guide.
The RTEMS BSP leon3 is configured without MMU (default for the
testsuite goal) and without networking. The image links a single
user task that prints a banner and exits cleanly.
ELF vs. PROM image
tero-emu --image accepts either a plain SPARC ELF (loaded into
RAM at its segment addresses, like a debugger) or an mkprom2 PROM
image (the bootloader-wrapped .rom that mirrors how real silicon
boots from PROM). Emulator::initialize() detects the ELF magic and
flattens the PROM image's PT_LOAD segments automatically. New RTEMS
guests in this repo follow the PROM path; the bundled hello-world.elf
uses the direct-ELF path.
2. Run it¶
Expected console output (on stdout):
*** BEGIN OF TEST HELLO WORLD ***
*** TEST VERSION: 5.x.y
*** TEST STATE: EXPECTED-PASS
*** TEST BUILD:
*** TEST TOOLS: 7.5.0 20191114 (RCC 1.3.2 [bcc-2.2.2-gcc])
Hello World
*** END OF TEST HELLO WORLD ***
And a halt summary on stderr:
What success looks like¶
| Signal | Meaning |
|---|---|
The banner and Hello World appear on stdout |
The BSP booted, the console UART is wired, and the user task ran. |
reason=DurationExpired (or DeadlineReached) |
The run ended because the time budget expired — a clean, expected ending. |
Exit code 0 |
Normal completion. |
reason=HaltedMode + exit code 5 |
The guest deliberately stopped (e.g. _exit/_CPU_Fatal_halt issuing ta 0 with traps disabled), or hit an unrecoverable fault. This is the guest's own doing, not an emulator failure; a register post-mortem of core 0 is dumped to stderr. |
For test scoring, an RTEMS testsuite program is counted PASS when its
captured UART output contains the exact string *** END OF TEST.
Why the CLI exits 0 even though RTEMS never calls exit()
In this configuration RTEMS returns to its idle thread, which
immediately enters power-down via wr %g0, %asr19. The emulator's
idle-time skip then fast-forwards
simulated time straight to the deadline. The run ends with
DurationExpired and exit code 0.
Pacing¶
tero-emu runs in real-time pacing mode by default: 1 second of
simulated time takes roughly 1 second of wall-clock time, so periodic
UART output appears at its scheduled intervals. For a faster
boot-and-exit cycle while iterating, pass --turbo to disable pacing:
3. Run the sptest integration suite¶
The repository can build a set of SPARC RTEMS sptests as ELFs (populated
locally under tests/guest-programs/rtems/sptests/bin/). The CTest
wrapper runs them and checks the captured UART:
A sptest is recorded PASS when its captured UART contains the exact
string *** END OF TEST.
4. Capture the UART programmatically¶
To integrate Tero into a CI pipeline, replace the default
StdoutCharDevice on the console UART with the test-support
CapturingCharDevice and assert on its contents:
#include "tero/runtime/emulator.hpp"
#include "tests/support/capturing_char_device.hpp"
auto cap = std::make_unique<tero::test_support::CapturingCharDevice>();
auto* ref = cap.get();
emu->set_character_device(std::move(cap)); // console UART = UART0
emu->initialize(); // ← latches the chardev; do it after
emu->load_elf("hello-world.elf");
emu->run_for(tero::SimTimeNs{2'000'000'000ULL});
if (ref->captured().find("*** END OF TEST") != std::string::npos) {
/* PASS */
}
The order matters: each APBUART latches its ICharacterDevice* during
initialize(). Set the chardev before initializing. See
UART and console for more capture, routing,
and suppression strategies.
What is happening under the hood?¶
The boot sequence on real GR712RC and on Tero is the same:
_startruns from the ELF entry point (typically0x40000000), or from the mkprom2 bootloader in PROM at address 0.- The RTEMS bootstrap probes the MemCtrl (FTMCTRL) for memory layout, programs the GPTimer prescaler for the system tick, and unmasks IRQs at the IRQMP.
- The first user task is created and scheduled.
printf/printkwrites through the APBUART data register; Tero's ApbUart peripheral forwards every byte to the injectedICharacterDevice.- The task ends, the idle thread halts each CPU via
wr %g0, %asr19, and the emulator skips simulated time to the next pending event.
For the deep dive on each of these, see Execution model, Traps and interrupts, and the peripheral reference.
Next: debug the guest with GDB¶
Once hello-world.elf boots, the natural next step is to attach a
debugger. Tero embeds a GDB Remote Serial Protocol stub:
# Terminal A — start the emulator with the stub listening
./build/src/app/tero-emu \
--image tests/guest-programs/rtems/hello-world/hello-world.elf \
--gdb-port 1234
# Terminal B — attach (point GDB at the ELF for symbols)
sparc-gaisler-rtems5-gdb tests/guest-programs/rtems/hello-world/hello-world.elf
(gdb) target remote :1234
(gdb) info threads # RTEMS-aware: shows task name / state / priority
(gdb) break Init
(gdb) c
GDB can connect at any time after the emulator starts (late-binding); no
--gdb-wait is needed unless you want to break on the very first
instruction. Full reference:
Debugging with GDB.