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