In the Creating Secure and Non-Secure projects tutorial, you have attempted to access a Secure (S) FlexComm0 (USART) peripheral from a Non-Secure (NS) code and failed with the SecureFault exception. This was expected, as TrustZone® for ARM®v8-M protects Secure resources from Non-Secure access.
Now imagine a use case where the platform manages (protects) access to all its peripherals and firmware logic and requires all 3rd party extensions, for example plugins or widgets, to be certified (approved) for use. The result of this approval process is some form of identification, a license key for instance, the untrusted code needs to supply to the trusted code to gain peripheral access and be able to communicate via USART. This kind of behavior can be achieved with the help of Non-Secure Callable (NSC) memory.
NSC is a type of Secure memory exclusively permitted to hold the Secure Gateway (SG) instruction that allows transition from NS to S state. When a Non-Secure program calls a function in the Secure side, the first instruction in the API must be an SG instruction. The Branch with exchange to Non-secure state (BXNS) will return execution to the Non-Secure side after the API call. While it’s possible for NSC memory to contain entire functions, its typical usage is holding tables of SG instructions with entry points, called veneers.
With GCC, ARMCC, ARMCLANG, IARCC, and LLVM compilers, you must specify the __attribute__((cmse_nonsecure_entry)) function attribute to declare an entry C/C++ function callable from NS state; SG and BXNS instructions are generated automatically. GNU linker puts the resulting code into the .gnu.sgstubs section aligned at 32 bytes.
With the solution outlined, you can reuse projects from the “TEE projects creation” tutorial to speed things up. To extend an existing project with NSC functions, the workflow is as follows:
Start with the Secure project conveniently named “Secure”.
If you attempt to build the S project now, you’ll receive several linker errors telling you the NSC library could not be built as there are no NSC functions (yet) including the name of the said library: Secure_CMSE_lib.o. You’re going to use it to configure the Non-Secure project named “Non-Secure”.
You will see “${workspace_loc:/Secure/Debug/Secure_CMSE_lib.o}” in the Secure Gateway Import Library field of the MCU Linker Setting dialog.
The source/Secure.c file already contains the sendSecureByte function implementation you need to make accessible through the NSC space. What’s missing is a few lines of code for its NSC equivalent and function prototype.
#ifndef NSC_API_H_
#define NSC_API_H_
#include <stdint.h>
void sendSecureByteNSC(uint8_t data);
#endif /* NSC_API_H_ */
#include <arm_cmse.h>
#include "fsl_debug_console.h"
#include "nsc_api.h"
#include "comm.h"
void __attribute__((cmse_nonsecure_entry)) sendSecureByteNSC(uint8_t data) {
if (cmse_nonsecure_caller()) {
PRINTF("sendSecureByteNSC called from NS space\r\n");
} else {
PRINTF("sendSecureByteNSC called from S space\r\n");
}
sendSecureByte(data);
}
#include "nsc_api.h"
…
USART_WriteByte((USART_Type *)FLEXCOMM0, 'n');
sendSecureByteNSC('n');
Once the code is running, each press of the WAKEUP (S2) button on the LPCXpresso55S69 board will display the “sendSecureByteNSC called from NS space” message in the IDE console and send a single character via USART instead of failing with the SecureFault exception.