I'm using TrustZone on RP2350 microcontroller. After setting up SAU to define secure and non-secure memory areas, I'm jumping to non-secure code with bxns
instruction.
The non-secure part of the firmware is compiled has its own vector table and I'm taking the entry addresses from it:
uint32_t *image_base = ...;
uint32_t sp = image_base[0];
uint32_t pc = image_base[1];
__asm__(
"msr msp_ns, %0\n\t"
"bxns %1" : : "r" (sp), "r" (pc) : "memory");
After the bxns instruction executes, the CPU jumps to crash handler. The SFSR
(secure fault status register) shows value 0x00000010
, indicating the INVTRAN
error:
Invalid transition flag. Sticky flag indicating that an exception was raised due to a branch that was not flagged as being domain crossing causing a transition from Secure to Non-secure memory.
How should I "flag" the branch?
I'm using TrustZone on RP2350 microcontroller. After setting up SAU to define secure and non-secure memory areas, I'm jumping to non-secure code with bxns
instruction.
The non-secure part of the firmware is compiled has its own vector table and I'm taking the entry addresses from it:
uint32_t *image_base = ...;
uint32_t sp = image_base[0];
uint32_t pc = image_base[1];
__asm__(
"msr msp_ns, %0\n\t"
"bxns %1" : : "r" (sp), "r" (pc) : "memory");
After the bxns instruction executes, the CPU jumps to crash handler. The SFSR
(secure fault status register) shows value 0x00000010
, indicating the INVTRAN
error:
Invalid transition flag. Sticky flag indicating that an exception was raised due to a branch that was not flagged as being domain crossing causing a transition from Secure to Non-secure memory.
How should I "flag" the branch?
Share Improve this question asked Mar 19 at 19:07 jpajpa 12.2k1 gold badge37 silver badges55 bronze badges 2- Hopefully you've left out the part of your code where registers are sanitized before transitioning to non-secure state...? – Nate Eldredge Commented Mar 19 at 19:36
- @NateEldredge Yes, and a lot of other init stuff. Maybe eventually I'll post something more complete, but that's a bit lot for a single question. – jpa Commented Mar 19 at 20:07
1 Answer
Reset to default 0From description of the bxns
instruction in Armv8-M Architecture Reference Manual:
Branch and Exchange Non-secure causes a branch to an address specified by a register. If bit[0] of the target address is 0, and the target address is not FNC_RETURN or EXC_RETURN, then the instruction causes a transition from Secure to Non-secure state. This variant of the instruction must only be used when the additional steps required to make such a transition safe have been taken.
Normally in ARMv8-m, the lowest bit of a branch address must be 1
, to indicate the thumb instruction mode. This applies also to the reset vector in the vector table. However, in the specific case of bxns
, it transfers to non-secure state only when the bottom bit is set to 0.
The target memory area has been configured as non-secure in SAU but because the bottom bit is set, the processor stays in secure mode. This triggers the fault, as secure mode cannot execute instructions from non-secure memory.
To properly execute the jump, the address must be modified:
__asm__(
"msr msp_ns, %0\n\t"
"bxns %1" : : "r" (sp), "r" (pc & ~1) : "memory");