Bare-Metal Example
The bare-metal host (host/bare_metal_arm/) is the simplest way to interact with Umbra. It runs a hand-coded round-robin loop that scans flash for enclaves, creates them via NSC veneers, and executes them until termination.
How It Works
main()
├── Scan NS flash (0x08040000–0x08080000) for UMBR magic at 4KB page boundaries
├── umbra_tee_create(addr) for each enclave found
└── Round-robin loop:
├── umbra_enclave_enter(id) → returns status
│ ├── SUSPENDED → enclave was preempted by Secure SysTick
│ ├── TERMINATED → print R0 result, mark done
│ └── FAULTED → print error, mark done
└── Repeat until all enclaves done
No RTOS, no heap, no interrupts in the NS world. The Secure SysTick handles enclave preemption; the host just re-enters suspended enclaves.
Building and Running
# Bare-metal is the default — no HOST_APP needed
source ./settings.sh
./rebuild_all.sh
./debug.sh
Expected UART Output
[UMBRASecureBoot] Secure Boot started
[UMBRASecureBoot] Kernel Initialized
[UMBRASecureBoot] Jumping to Non-Secure World
[USER] Hello Non-Secure World!
[USER] Enclave created
[USER] Enclave preempted (SysTick)
[USER] Enclave preempted (SysTick)
...
[USER] Enclave terminated! R0=0x72CA33A8
[USER] All enclaves done
The number of Enclave preempted lines varies depending on the SysTick quantum (~10ms at 4 MHz MSI).
File Structure
host/bare_metal_arm/
├── src/
│ ├── main.c Entry point, enclave header, round-robin scheduler
│ └── startup.s NS vector table + Reset_Handler (.data/.bss init)
├── app/
│ └── fibonacci.c Enclave payload (Fibonacci + filler functions)
├── inc/
│ └── fibonacci.h
├── linker/
│ ├── memory.ld MCU memory regions + Umbra aliases
│ └── host.ld Section layout + NSC veneer addresses (PROVIDE)
└── Makefile
Key Design Points
- No vector table fetch: the NS VTOR is not used at runtime — the bare-metal host never triggers SVC, PendSV, or SysTick exceptions. All scheduling is done cooperatively via the round-robin loop.
- Enclave header in flash: the 48-byte header (magic, trust level, HMAC) is placed in
._enclave_headerby a section attribute.protect_enclave.pyoverwrites the HMAC field at build time. - NSC veneer addresses: hardcoded via
PROVIDE()inhost.ld. These must be updated if the Secure boot is rebuilt and veneer offsets change.