1 /* 2 * Copyright (c) 2020 Nordic Semiconductor ASA 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 /** 8 * @file 9 * @brief TrustZone API for use in nonsecure firmware 10 * 11 * TrustZone API for Cortex-M CPUs implementing the Security Extension. 12 * The following API can be used by the nonsecure firmware to interact with the 13 * secure firmware. 14 */ 15 16 #ifndef ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_NS_H_ 17 #define ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_NS_H_ 18 19 #ifdef _ASMLANGUAGE 20 21 /* nothing */ 22 23 #else 24 25 /** 26 * @brief Macro for "sandwiching" a function call (@p name) between two other 27 * calls 28 * 29 * This macro should be called via @ref __TZ_WRAP_FUNC. 30 * 31 * This macro creates the function body of an "outer" function which behaves 32 * exactly like the wrapped function (@p name), except that the preface function 33 * is called before, and the postface function afterwards. 34 * 35 * @param preface The function to call first. Must have no parameters and no 36 * return value. 37 * @param name The main function, i.e. the function to wrap. This function 38 * will receive the arguments, and its return value will be 39 * returned. 40 * @param postface The function to call last. Must have no parameters and no 41 * return value. 42 * @param store_lr The assembly instruction for storing away the LR value 43 * before the functions are called. This instruction must leave 44 * r0-r3 unmodified. 45 * @param load_lr The assembly instruction for restoring the LR value after 46 * the functions have been called. This instruction must leave 47 * r0-r3 unmodified. 48 */ 49 #define __TZ_WRAP_FUNC_RAW(preface, name, postface, store_lr, load_lr) \ 50 __asm__ volatile(".global " #preface "; .type " #preface ", %function"); \ 51 __asm__ volatile(".global " #name "; .type " #name ", %function"); \ 52 __asm__ volatile(".global " #postface "; .type " #postface ", %function"); \ 53 __asm__ volatile(store_lr "\n\t" \ 54 "push {r0-r3}\n\t" \ 55 "bl " #preface "\n\t" \ 56 "pop {r0-r3}\n\t" \ 57 "bl " #name "\n\t" \ 58 "push {r0-r3}\n\t" \ 59 "bl " #postface "\n\t" \ 60 "pop {r0-r3}\n\t" load_lr "\n\t" ::); 61 62 /** 63 * @brief Macro for "sandwiching" a function call (@p name) in two other calls 64 * 65 * @pre The wrapped function MUST not pass arguments or return values via 66 * the stack. I.e. the arguments and return values must each fit within 4 67 * words, after accounting for alignment. 68 * Since nothing is passed on the stack, the stack can safely be used to 69 * store LR. 70 * 71 * Usage example: 72 * 73 * int foo(char *arg); // Implemented elsewhere. 74 * int __attribute__((naked)) foo_wrapped(char *arg) 75 * { 76 * __TZ_WRAP_FUNC(bar, foo, baz) 77 * } 78 * 79 * is equivalent to 80 * 81 * int foo(char *arg); // Implemented elsewhere. 82 * int foo_wrapped(char *arg) 83 * { 84 * bar(); 85 * int res = foo(arg); 86 * baz(); 87 * return res; 88 * } 89 * 90 * @note __attribute__((naked)) is not mandatory, but without it, GCC gives a 91 * warning for functions with a return value. It also reduces flash use. 92 * 93 * See @ref __TZ_WRAP_FUNC_RAW for more information. 94 */ 95 #define __TZ_WRAP_FUNC(preface, name, postface) \ 96 __TZ_WRAP_FUNC_RAW(preface, name, postface, "push {r4, lr}", "pop {r4, pc}") 97 98 #ifdef CONFIG_ARM_FIRMWARE_USES_SECURE_ENTRY_FUNCS 99 /** 100 * @brief Create a thread safe wrapper function for a non-secure entry function 101 * 102 * This locks the scheduler before calling the function by wrapping the NS entry 103 * function in @ref k_sched_lock / @ref k_sched_unlock, using 104 * @ref __TZ_WRAP_FUNC. 105 * 106 * In non-secure code: 107 * 108 * int foo(char *arg); // Declaration of entry function. 109 * TZ_THREAD_SAFE_NONSECURE_ENTRY_FUNC(foo_safe, int, foo, char *arg) 110 * 111 * Usage in non-secure code: 112 * 113 * int ret = foo_safe("my arg"); 114 * 115 * If NS entry functions are called without such a wrapper, and a thread switch 116 * happens while execution is in the secure binary, the app will possibly crash 117 * upon returning to the non-secure binary. 118 * 119 * @param ret The return type of the NS entry function. 120 * @param name The desired name of the safe function. This assumes there is a 121 * corresponding NS entry function called nsc_name. 122 * @param ... The rest of the signature of the function. This must be the same 123 * signature as the corresponding NS entry function. 124 */ 125 #define TZ_THREAD_SAFE_NONSECURE_ENTRY_FUNC(name, ret, nsc_name, ...) \ 126 ret __attribute__((naked)) name(__VA_ARGS__) \ 127 { \ 128 __TZ_WRAP_FUNC(k_sched_lock, nsc_name, k_sched_unlock); \ 129 } 130 131 #endif /* CONFIG_ARM_FIRMWARE_USES_SECURE_ENTRY_FUNCS */ 132 133 #endif /* _ASMLANGUAGE */ 134 #endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_NS_H_ */ 135