/* * Copyright (c) 2020 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ /** * @file * @brief TrustZone API for use in nonsecure firmware * * TrustZone API for Cortex-M CPUs implementing the Security Extension. * The following API can be used by the nonsecure firmware to interact with the * secure firmware. */ #ifndef ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_NS_H_ #define ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_NS_H_ #ifdef _ASMLANGUAGE /* nothing */ #else /** * @brief Macro for "sandwiching" a function call (@p name) between two other * calls * * This macro should be called via @ref __TZ_WRAP_FUNC. * * This macro creates the function body of an "outer" function which behaves * exactly like the wrapped function (@p name), except that the preface function * is called before, and the postface function afterwards. * * @param preface The function to call first. Must have no parameters and no * return value. * @param name The main function, i.e. the function to wrap. This function * will receive the arguments, and its return value will be * returned. * @param postface The function to call last. Must have no parameters and no * return value. * @param store_lr The assembly instruction for storing away the LR value * before the functions are called. This instruction must leave * r0-r3 unmodified. * @param load_lr The assembly instruction for restoring the LR value after * the functions have been called. This instruction must leave * r0-r3 unmodified. */ #define __TZ_WRAP_FUNC_RAW(preface, name, postface, store_lr, load_lr) \ __asm__ volatile( \ ".global "#preface"; .type "#preface", %function"); \ __asm__ volatile( \ ".global "#name"; .type "#name", %function"); \ __asm__ volatile( \ ".global "#postface"; .type "#postface", %function"); \ __asm__ volatile( \ store_lr "\n\t" \ "push {r0-r3}\n\t" \ "bl " #preface "\n\t" \ "pop {r0-r3}\n\t" \ "bl " #name " \n\t" \ "push {r0-r3}\n\t" \ "bl " #postface "\n\t" \ "pop {r0-r3}\n\t" \ load_lr "\n\t" \ ::); /** * @brief Macro for "sandwiching" a function call (@p name) in two other calls * * @pre The wrapped function MUST not pass arguments or return values via * the stack. I.e. the arguments and return values must each fit within 4 * words, after accounting for alignment. * Since nothing is passed on the stack, the stack can safely be used to * store LR. * * Usage example: * * int foo(char *arg); // Implemented elsewhere. * int __attribute__((naked)) foo_wrapped(char *arg) * { * __TZ_WRAP_FUNC(bar, foo, baz) * } * * is equivalent to * * int foo(char *arg); // Implemented elsewhere. * int foo_wrapped(char *arg) * { * bar(); * int res = foo(arg); * baz(); * return res; * } * * @note __attribute__((naked)) is not mandatory, but without it, GCC gives a * warning for functions with a return value. It also reduces flash use. * * See @ref __TZ_WRAP_FUNC_RAW for more information. */ #define __TZ_WRAP_FUNC(preface, name, postface) \ __TZ_WRAP_FUNC_RAW(preface, name, postface, "push {r4, lr}", \ "pop {r4, pc}") #ifdef CONFIG_ARM_FIRMWARE_USES_SECURE_ENTRY_FUNCS /** * @brief Create a thread safe wrapper function for a non-secure entry function * * This locks the scheduler before calling the function by wrapping the NS entry * function in @ref k_sched_lock / @ref k_sched_unlock, using * @ref __TZ_WRAP_FUNC. * * In non-secure code: * * int foo(char *arg); // Declaration of entry function. * TZ_THREAD_SAFE_NONSECURE_ENTRY_FUNC(foo_safe, int, foo, char *arg) * * Usage in non-secure code: * * int ret = foo_safe("my arg"); * * If NS entry functions are called without such a wrapper, and a thread switch * happens while execution is in the secure binary, the app will possibly crash * upon returning to the non-secure binary. * * @param ret The return type of the NS entry function. * @param name The desired name of the safe function. This assumes there is a * corresponding NS entry function called nsc_name. * @param ... The rest of the signature of the function. This must be the same * signature as the corresponding NS entry function. */ #define TZ_THREAD_SAFE_NONSECURE_ENTRY_FUNC(name, ret, nsc_name, ...) \ ret __attribute__((naked)) name(__VA_ARGS__) \ { \ __TZ_WRAP_FUNC(k_sched_lock, nsc_name, k_sched_unlock); \ } #endif /* CONFIG_ARM_FIRMWARE_USES_SECURE_ENTRY_FUNCS */ #endif /* _ASMLANGUAGE */ #endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_NS_H_ */