This workspace contains two no_std Cortex-M projects for an STM32L552-class Cortex-M33 target:
secure/: secure-world imagenonsecure/: non-secure-world imagextask/: host-side helper used to build both images in the right order
The secure image:
- prints a semihosting banner from the secure world
- configures a simple SAU layout
- installs the non-secure VTOR
- initializes the non-secure MSP
- branches to the non-secure reset handler
- exports one secure callable function through an NSC veneer
The non-secure image:
- prints a semihosting banner from the non-secure world
- calls the secure veneer-backed function
This example now follows the same TrustZone partitioning as the reference C project:
- Secure flash alias:
0x0C00_0000 .. 0x0C03_DFFF - NSC veneers forced to:
0x0C03_E000 .. 0x0C03_FFFF - Non-secure flash:
0x0804_0000 .. 0x0807_FFFF - Secure SRAM linker region:
0x3000_0000 .. 0x3001_7FFF - Non-secure SRAM linker region:
0x2001_8000 .. 0x2002_FFFF - SAU non-secure SRAM window:
0x2001_8000 .. 0x2003_FFFF
The secure project also mirrors the C project's GTZC policy:
LPUART1andVREFBUFare secure, non-privileged- lower 96 KiB of
SRAM1remain secure - upper 96 KiB of
SRAM1are non-secure - all of
SRAM2is non-secure
Adjust the linker scripts under secure/ and nonsecure/ if your TrustZone option bytes or board layout differ.
Build the secure image:
cd secure
cargo buildThat produces the secure import library / veneer object at:
target/thumbv8m.main-none-eabihf/debug/veneer.o
Build the non-secure image against the secure veneer object:
cd nonsecure
cargo buildIf you want a custom veneer path, set:
SECURE_VENEER=/path/to/veneer.o cargo buildUse the workspace helper:
cargo run -p xtask -- buildOr use the convenience shell script from the workspace root:
./build.shThere is also a Cargo alias at the workspace root:
cargo tz-buildRelease mode:
cargo run -p xtask -- build --releaseOr:
cargo tz-build-releaseOr:
./build.sh --releaseThe helper builds secure/ first, then passes the generated veneer.o into the nonsecure/ build.
It also emits a merged HEX image at target/combined-debug.hex or target/combined-release.hex.
The workspace uses one shared ./target directory. A plain cargo clean at the
workspace root cleans the default host-side xtask artifacts; use the workspace
helper to clean the firmware target directory as well.
To clean all build artifacts together, use:
cargo tz-cleanOr:
./clean.shThis removes:
./target
For an interactive OpenOCD + GDB session, use:
./debug.sh serverin one terminal, then:
./debug.sh gdbin another.
The helper:
- starts
openocdwith a GDB server on:3333 - loads the secure ELF into
gdb-multiarch - adds non-secure symbols from the non-secure ELF at
0x08040000 - issues
monitor reset haltautomatically
If the images are already built and flashed:
./debug.sh --no-build --no-flash server
./debug.sh gdbThe workspace includes a convenience script for the NUCLEO-L552ZE board:
./flash.shThis script:
- builds the secure and non-secure images unless
--no-buildis passed - flashes both the secure and non-secure ELFs with
openocdin a single session - resets the target at the end
Release flashing:
./flash.sh --releaseTo launch the project and forward semihosting output to your terminal:
./semihost.shRelease mode:
./semihost.sh --releaseIf the images are already built and flashed:
./semihost.sh --no-build --no-flashsemihost.sh uses ./flash.sh for programming, then uses openocd only for
attach, reset, and semihost output.
If you need to choose a specific debug probe or SWD speed:
./flash.sh --probe <serial-or-probe-selector> --speed 4000If the device is hard to attach to, try:
./flash.sh --connect-under-resetThe current tooling choice is based on observed behavior on this board:
openocdreliably programmed and verified both the secure and non-secure ELFs
Flashing the two ELFs is not sufficient by itself on STM32L5. The board's TrustZone-related option bytes and flash partitioning must match the layout used by this example:
- secure image flash physical window:
0x0800_0000 .. 0x0803_DFFF - secure image flash alias window:
0x0C00_0000 .. 0x0C03_DFFF - NSC veneers at:
0x0803_E000 .. 0x0803_FFFFphysical,0x0C03_E000 .. 0x0C03_FFFFalias - non-secure flash window:
0x0804_0000 .. 0x0807_FFFF - secure SRAM linker region:
0x3000_0000 .. 0x3001_7FFF - non-secure SRAM linker region:
0x2001_8000 .. 0x2002_FFFF
In practice, that means:
- TrustZone must be enabled on the STM32L552
- the secure watermark / memory attribution option bytes must be configured consistently with the linker scripts
NSBOOTADD0should point to the non-secure image base at0x0804_0000
This repository automates image flashing with openocd, semihost bring-up
with openocd, and includes a separate helper for STM32L5 option-byte
provisioning with STM32CubeProgrammer CLI:
./provision.shTo inspect the current option bytes only:
./provision.sh --display-onlyThe detailed board-preparation notes are in docs/board_setup_nucleo_l552ze.md.
secure/uses nightly because the secure gateway export relies oncmse_nonsecure_entry.- Both images use
build-stdso you do not need a preinstalledthumbv8m.main-none-eabihfstandard library target. - This workspace was written to be semihosting-friendly for debug bring-up. On hardware you will need a debugger/server that supports semihosting.
- Current nightly emits a warning for
-C target-feature=+trustzone; the build still succeeds and is expected for this example.
