Skip to content

Improve trustzone support: take2#671

Merged
jonathanpallant merged 9 commits into
masterfrom
improve-trustzone-support-take2
Jul 21, 2026
Merged

Improve trustzone support: take2#671
jonathanpallant merged 9 commits into
masterfrom
improve-trustzone-support-take2

Conversation

@jonathanpallant

Copy link
Copy Markdown
Contributor

This PR merges #648 and #666 into one cohesive whole.

leftger and others added 6 commits July 21, 2026 11:55
- Derive Copy, Clone, PartialEq, Eq on SauRegion and SauRegionAttribute
- SAU::disable_allns(): set CTRL.ALLNS=1, ENABLE=0 (all memory Non-Secure)
- SAU::init(regions): disable SAU, program up to 8 regions, re-enable
- jump_to_nonsecure(ns_vtor): Secure→Non-Secure boot handoff via BXNS

These cover the remaining ARMv8-M TrustZone boot sequence after SAU region
programming: disabling the SAU for NS-only systems, bulk-initialising regions
without manually looping set_region, and transferring control to the NS image.
Enables non-secure alias for SCB
The values aren't very useful if you cannot access the fields outside
the cortex-m crate.
Also moved the BXNS instruction into a global asm block to avoid issues
with erasing registers that LLVM wants to use.
@jonathanpallant
jonathanpallant force-pushed the improve-trustzone-support-take2 branch from 1b02638 to d8c1b60 Compare July 21, 2026 11:34
Comment thread cortex-m/src/asm.rs
I don't imagine you could leak a lot from secure mode with those, but
we should try and leak nothing.
@jonathanpallant

Copy link
Copy Markdown
Contributor Author

I have tested this bootloader function on an STM32U5:

Hello, this is secure-loader. Configuring peripherals...
...SAU configured
...GTZC1 configured
Booting NS application at 0x08200000...
SECURE FAULT:
- SFAR = 20000000
- Attribution Unit Violation
#[cortex_m_rt::entry]
fn main() -> ! {
    let mut bsp: bsp::SecureBoard = bsp::SecureBoard::new();

    // Enable secure fault handler
    bsp.scb
        .enable(cortex_m::peripheral::scb::Exception::SecureFault);

    // Say hello
    println!("Hello, this is secure-loader. Configuring peripherals...");

    // Configure peripherals
    bsp.configure_sau();
    println!("...SAU configured");
    bsp.set_sram3_nonsecure();
    println!("...GTZC1 configured");

    let ns_app_base = bsp::hal::ns_addr::FLASH2_START;
    println!("Booting NS application at 0x{:08x}...", ns_app_base);
    // Boot nonsecure world
    unsafe {
        cortex_m::asm::bootload_ns(ns_app_base as *const u32, bsp.scb_ns);
    }
}

@jonathanpallant

jonathanpallant commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

VLSTM is apparently a NOP if you don't have an FPU, so maybe we should unconditionally do it? Avoids issues if you were using the FPU despite running a soft-float (EABI) target.

See https://developer.arm.com/documentation/dui0801/l/Floating-point-Instructions--32-bit-/VLSTM--A32-

@diondokter

Copy link
Copy Markdown
Contributor

That sounds good. Keeps complexity low and it always does the correct thing. The only cost is 2 bytes of flash and 1 clock cycle. Easily worth it

It should be a NOP if you don't have FPU support. And this is better
because someone might have been using the FPU on an EABI target.
@jonathanpallant

Copy link
Copy Markdown
Contributor Author

These changes also allow a SecureFault handler that looks like this:

#[cortex_m_rt::exception]
fn SecureFault() {
    println!("SECURE FAULT:");
    // Safety: No-one else is using the SAU, so this won't race, plus the registers we want are read-only
    let sau = unsafe { &*cortex_m::peripheral::SAU::PTR };
    let sfsr = sau.sfsr.read();
    if sfsr.sfarvalid() {
        println!("- SFAR = {:08x}", sau.sfar.read().address());
    }
    if sfsr.invep() {
        println!("- Invalid Entry Point");
    }
    if sfsr.invis() {
        println!("- Invalid Integrity Signature");
    }
    if sfsr.inver() {
        println!("- Invalid Exception Return");
    }
    if sfsr.auviol() {
        println!("- Attribution Unit Violation");
    }
    if sfsr.invtran() {
        println!("- Invalid Transition");
    }
    if sfsr.lsperr() {
        println!("- Lazy state preservation error");
    }
    if sfsr.lserr() {
        println!("- Lazy state error");
    }
    loop {}
}

@therealprof therealprof left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@jonathanpallant
jonathanpallant added this pull request to the merge queue Jul 21, 2026
Merged via the queue into master with commit 4200951 Jul 21, 2026
11 checks passed
@jonathanpallant
jonathanpallant deleted the improve-trustzone-support-take2 branch July 21, 2026 12:53
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.

4 participants