Skip to content

feat(tock-l552): TockOS host port on STM32L552 (#41)#52

Merged
salva00 merged 1 commit into
mainfrom
41-featurehost-tockos-host-new
May 26, 2026
Merged

feat(tock-l552): TockOS host port on STM32L552 (#41)#52
salva00 merged 1 commit into
mainfrom
41-featurehost-tockos-host-new

Conversation

@salva00
Copy link
Copy Markdown
Collaborator

@salva00 salva00 commented May 26, 2026

Brings up the Tock kernel as an Umbra Non-Secure host on NUCLEO-L552ZE-Q. A libtock-rs userspace app drives enclaves through a custom Tock capsule that wraps the four NSC veneers; Umbra Secure programs the NS-MPU during boot so Tock's MPU layer is a no-op stub.

Hardware-verified end-to-end on the real board:

  • fibonacci enclave: PASS
  • TACLeBench paper suite (binarysearch, bsort, countnegative, ndes, statemate): 5/5 PASS at FreeRTOS-parity wall-clock times
  • HOST_APP=tock ./tools/test_taclebench.sh integrates with the standard per-bench harness (heartbeat + drift assertions extended to tock)

Workspace layout

  • host/stm32l552/tock/ — Cargo workspace
    • chips/stm32l5xx/, chips/stm32l552/ — chip glue (RCC, GPIO, LPUART1, vectors)
    • capsules/umbra/ — NSC syscall driver capsule + NoopMpu stub
    • boards/nucleo_l552ze_q_umbra/ — Tock board crate (main, fault dumper, raw_print, heartbeat, layout.ld)
    • apps/enclave_demo/ — libtock-rs TBF app (multi-enclave scan loop)
    • enclave_payload/ — fibonacci enclave bundled at 0x08078000
  • Submodules: lib/tock @ b35fad8 master plus a vendor patch on MuxUart::do_next_op (3f61f85f) for sync-callback ordering; lib/libtock-rs @ 0766d8c
  • Toolchain: nightly-2026-05-19

Capsule API (DRIVER_NUM 0xA0000)

cmd 0 — driver presence check cmd 1 — umbra_enclave_create(base_addr) cmd 2 — umbra_enclave_enter(enclave_id) cmd 3 — umbra_enclave_exit(enclave_id) cmd 4 — umbra_enclave_status(enclave_id) cmd 5 — probe UMBR magic at flash addr (apps can't dereference flash under Tock's MPU sandbox) cmd 6 — dump DWT drift stats over raw_print

Every command beyond presence-check returns CommandReturn::success() and delivers its u32 result through subscribe slot 0 as an upcall.

NSC veneer register barrier

Empirically the SG/BXNS round-trip through the Umbra NSC veneers does not preserve r4-r11 the way Rust's extern "C" ABI assumes — rustc + LLVM keeps &self in r5 across bl umbra_enclave_create and faults on the next dereference with SecureFault.AUVIOL (Secure-state addresses leak into NS scratch registers along the way). The capsule wraps each veneer call in inline asm that manually push/pops r4-r11 around the blx and lists r4/r5/r8-r11 as clobbered, forcing LLVM to spill live values before the call. Bare-metal C and FreeRTOS hosts on the same chip aren't affected because GCC's codegen happens to spill differently.

Heartbeat + DWT drift instrumentation

The board owns NS SysTick exclusively (Tock's SchedulerTimer is the never-expires () stub), configured once at boot exactly like FreeRTOS's prvSetupTimerInterrupt. The SysTick handler updates per-tick stats (DWT delta, max, buckets, heartbeat counter) atomically; all [HEARTBEAT] and [DRIFT] lines are emitted in one atomic burst via the capsule's cmd=6 dump path at end-of-run rather than from IRQ context, so they never splice into Umbra Secure's own UART writes.

Umbra Secure changes

Static NS-MPU layout for STM32L552 (6 regions per the spec's region 3/4 split: kernel-priv-RW + app-unpriv-RW, with EFBC and SRAM2 reserved as Secure-only):

  • src/hardware/architecture/arm/src/mpu.rs — NS_MPU_BASE_ADDR + new_with_base() + enable_strict() + program_ns_mpu() helper
  • src/hardware/platform/stm32l552/boot/src/ns_mpu_layout.rs (new) — NS_MPU_LAYOUT_L552 const
  • src/hardware/platform/stm32l552/boot/src/platform_impl.rs — call program_ns_mpu() from configure_ns_boot() before jumping to NS

Harness integration

tools/test_taclebench.sh:

  • HOST_APP=tock case wired (HOST_LOG_PREFIX="[TOCK]")
  • Heartbeat liveness + drift bounds + healthy% assertions extended from freertos to also cover tock
  • awk calls prefixed with LC_ALL=C to tolerate the 0xFE world-transition glitch byte under UTF-8 locales

Documentation

  • book/src/examples/tock.md (new) — full architecture walkthrough, register barrier explanation, heartbeat/drift section, TACLeBench integration, submodule pins
  • SUMMARY.md, examples/README.md, introduction.md, build-and-run.md, crate-structure.md, top-level README.md all updated to list the Tock host alongside bare_metal / freertos / object_detection

Closes #41.

Brings up the Tock kernel as an Umbra Non-Secure host on
NUCLEO-L552ZE-Q. A libtock-rs userspace app drives enclaves through a
custom Tock capsule that wraps the four NSC veneers; Umbra Secure
programs the NS-MPU during boot so Tock's MPU layer is a no-op stub.

Hardware-verified end-to-end on the real board:
- fibonacci enclave: PASS
- TACLeBench paper suite (binarysearch, bsort, countnegative, ndes,
  statemate): 5/5 PASS at FreeRTOS-parity wall-clock times
- HOST_APP=tock ./tools/test_taclebench.sh integrates with the standard
  per-bench harness (heartbeat + drift assertions extended to tock)

## Workspace layout

- host/stm32l552/tock/ — Cargo workspace
  - chips/stm32l5xx/, chips/stm32l552/ — chip glue (RCC, GPIO, LPUART1,
    vectors)
  - capsules/umbra/ — NSC syscall driver capsule + NoopMpu stub
  - boards/nucleo_l552ze_q_umbra/ — Tock board crate (main, fault dumper,
    raw_print, heartbeat, layout.ld)
  - apps/enclave_demo/ — libtock-rs TBF app (multi-enclave scan loop)
  - enclave_payload/ — fibonacci enclave bundled at 0x08078000
- Submodules: lib/tock @ b35fad8 master plus a vendor patch on
  MuxUart::do_next_op (3f61f85f) for sync-callback ordering;
  lib/libtock-rs @ 0766d8c
- Toolchain: nightly-2026-05-19

## Capsule API (DRIVER_NUM 0xA0000)

  cmd 0 — driver presence check
  cmd 1 — umbra_enclave_create(base_addr)
  cmd 2 — umbra_enclave_enter(enclave_id)
  cmd 3 — umbra_enclave_exit(enclave_id)
  cmd 4 — umbra_enclave_status(enclave_id)
  cmd 5 — probe UMBR magic at flash addr (apps can't dereference flash
          under Tock's MPU sandbox)
  cmd 6 — dump DWT drift stats over raw_print

Every command beyond presence-check returns CommandReturn::success() and
delivers its u32 result through subscribe slot 0 as an upcall.

## NSC veneer register barrier

Empirically the SG/BXNS round-trip through the Umbra NSC veneers does
not preserve r4-r11 the way Rust's extern "C" ABI assumes — rustc + LLVM
keeps &self in r5 across bl umbra_enclave_create and faults on the next
dereference with SecureFault.AUVIOL (Secure-state addresses leak into NS
scratch registers along the way). The capsule wraps each veneer call in
inline asm that manually push/pops r4-r11 around the blx and lists
r4/r5/r8-r11 as clobbered, forcing LLVM to spill live values before the
call. Bare-metal C and FreeRTOS hosts on the same chip aren't affected
because GCC's codegen happens to spill differently.

## Heartbeat + DWT drift instrumentation

The board owns NS SysTick exclusively (Tock's SchedulerTimer is the
never-expires () stub), configured once at boot exactly like FreeRTOS's
prvSetupTimerInterrupt. The SysTick handler updates per-tick stats
(DWT delta, max, buckets, heartbeat counter) atomically; all [HEARTBEAT]
and [DRIFT] lines are emitted in one atomic burst via the capsule's
cmd=6 dump path at end-of-run rather than from IRQ context, so they
never splice into Umbra Secure's own UART writes.

## Umbra Secure changes

Static NS-MPU layout for STM32L552 (6 regions per the spec's region 3/4
split: kernel-priv-RW + app-unpriv-RW, with EFBC and SRAM2 reserved as
Secure-only):
- src/hardware/architecture/arm/src/mpu.rs — NS_MPU_BASE_ADDR +
  new_with_base() + enable_strict() + program_ns_mpu() helper
- src/hardware/platform/stm32l552/boot/src/ns_mpu_layout.rs (new) —
  NS_MPU_LAYOUT_L552 const
- src/hardware/platform/stm32l552/boot/src/platform_impl.rs — call
  program_ns_mpu() from configure_ns_boot() before jumping to NS

## Harness integration

tools/test_taclebench.sh:
- HOST_APP=tock case wired (HOST_LOG_PREFIX="[TOCK]")
- Heartbeat liveness + drift bounds + healthy% assertions extended from
  freertos to also cover tock
- awk calls prefixed with LC_ALL=C to tolerate the 0xFE world-transition
  glitch byte under UTF-8 locales

## Documentation

- book/src/examples/tock.md (new) — full architecture walkthrough,
  register barrier explanation, heartbeat/drift section, TACLeBench
  integration, submodule pins
- SUMMARY.md, examples/README.md, introduction.md, build-and-run.md,
  crate-structure.md, top-level README.md all updated to list the Tock
  host alongside bare_metal / freertos / object_detection

Closes #41.
@salva00 salva00 linked an issue May 26, 2026 that may be closed by this pull request
@salva00 salva00 merged commit 510b931 into main May 26, 2026
30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[feature/host] TockOS host

1 participant