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( \ 51 ".global "#preface"; .type "#preface", %function"); \ 52 __asm__ volatile( \ 53 ".global "#name"; .type "#name", %function"); \ 54 __asm__ volatile( \ 55 ".global "#postface"; .type "#postface", %function"); \ 56 __asm__ volatile( \ 57 store_lr "\n\t" \ 58 "push {r0-r3}\n\t" \ 59 "bl " #preface "\n\t" \ 60 "pop {r0-r3}\n\t" \ 61 "bl " #name " \n\t" \ 62 "push {r0-r3}\n\t" \ 63 "bl " #postface "\n\t" \ 64 "pop {r0-r3}\n\t" \ 65 load_lr "\n\t" \ 66 ::); 67 68 /** 69 * @brief Macro for "sandwiching" a function call (@p name) in two other calls 70 * 71 * @pre The wrapped function MUST not pass arguments or return values via 72 * the stack. I.e. the arguments and return values must each fit within 4 73 * words, after accounting for alignment. 74 * Since nothing is passed on the stack, the stack can safely be used to 75 * store LR. 76 * 77 * Usage example: 78 * 79 * int foo(char *arg); // Implemented elsewhere. 80 * int __attribute__((naked)) foo_wrapped(char *arg) 81 * { 82 * __TZ_WRAP_FUNC(bar, foo, baz) 83 * } 84 * 85 * is equivalent to 86 * 87 * int foo(char *arg); // Implemented elsewhere. 88 * int foo_wrapped(char *arg) 89 * { 90 * bar(); 91 * int res = foo(arg); 92 * baz(); 93 * return res; 94 * } 95 * 96 * @note __attribute__((naked)) is not mandatory, but without it, GCC gives a 97 * warning for functions with a return value. It also reduces flash use. 98 * 99 * See @ref __TZ_WRAP_FUNC_RAW for more information. 100 */ 101 #define __TZ_WRAP_FUNC(preface, name, postface) \ 102 __TZ_WRAP_FUNC_RAW(preface, name, postface, "push {r4, lr}", \ 103 "pop {r4, pc}") 104 105 106 #ifdef CONFIG_ARM_FIRMWARE_USES_SECURE_ENTRY_FUNCS 107 /** 108 * @brief Create a thread safe wrapper function for a non-secure entry function 109 * 110 * This locks the scheduler before calling the function by wrapping the NS entry 111 * function in @ref k_sched_lock / @ref k_sched_unlock, using 112 * @ref __TZ_WRAP_FUNC. 113 * 114 * In non-secure code: 115 * 116 * int foo(char *arg); // Declaration of entry function. 117 * TZ_THREAD_SAFE_NONSECURE_ENTRY_FUNC(foo_safe, int, foo, char *arg) 118 * 119 * Usage in non-secure code: 120 * 121 * int ret = foo_safe("my arg"); 122 * 123 * If NS entry functions are called without such a wrapper, and a thread switch 124 * happens while execution is in the secure binary, the app will possibly crash 125 * upon returning to the non-secure binary. 126 * 127 * @param ret The return type of the NS entry function. 128 * @param name The desired name of the safe function. This assumes there is a 129 * corresponding NS entry function called nsc_name. 130 * @param ... The rest of the signature of the function. This must be the same 131 * signature as the corresponding NS entry function. 132 */ 133 #define TZ_THREAD_SAFE_NONSECURE_ENTRY_FUNC(name, ret, nsc_name, ...) \ 134 ret __attribute__((naked)) name(__VA_ARGS__) \ 135 { \ 136 __TZ_WRAP_FUNC(k_sched_lock, nsc_name, k_sched_unlock); \ 137 } 138 139 #endif /* CONFIG_ARM_FIRMWARE_USES_SECURE_ENTRY_FUNCS */ 140 141 #endif /* _ASMLANGUAGE */ 142 #endif /* ZEPHYR_ARCH_ARM_INCLUDE_AARCH32_CORTEX_M_TZ_NS_H_ */ 143