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