blob: dfa73c12061fc3c05f9ebd893331333a92ce2f29 [file] [log] [blame]
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +00001/*
2 * Copyright (c) 2017, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8#include <stdio.h>
9#include <stdint.h>
10#include <string.h>
11#include <stdbool.h>
12
13#include "cmsis.h"
14#include "tfm_api.h"
15#include "cmsis_os2.h"
16
17#include "tfm_integ_test.h"
18#include "test/framework/integ_test.h"
19
20#ifdef CORE_TEST_INTERACTIVE
21#include "test/test_services/tfm_core_test/core_test_defs.h"
22#include "test/test_services/tfm_core_test/tfm_ss_core_test_veneers.h"
23#include "tfm_ns_svc.h"
24
25#define TRY_SFN(fn, ...) \
26 do { \
27 enum tfm_status_e res = (enum tfm_status_e) fn(__VA_ARGS__); \
28 switch(res) { \
29 case TFM_SUCCESS: \
30 LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") successful!!"); \
31 break; \
32 case TFM_SERVICE_PENDED: \
33 LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") pended!!"); \
34 break; \
35 case TFM_ERROR_SERVICE_ALREADY_PENDED: \
36 LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") failed, already pended!!"); \
37 break; \
38 case TFM_ERROR_SECURE_DOMAIN_LOCKED: \
39 LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") failed, S domain locked!!"); \
40 break; \
41 case TFM_ERROR_NS_THREAD_MODE_CALL: \
42 LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") failed, NS thread mode!!"); \
43 break; \
44 default: \
45 LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") failed, generic!!"); \
46 } \
47 } while(0)
48/**
49 * \brief SVC_SECURE_DECREMENT_NS_LOCK_1
50 *
51 */
52void svc_secure_decrement_ns_lock_1(void)
53{
54 TRY_SFN(tfm_core_test_sfn, CORE_TEST_ID_BLOCK, 0x1, 0x1, 0x1);
55}
56
57/**
58 * \brief SVC_SECURE_DECREMENT_NS_LOCK_2
59 *
60 */
61void svc_secure_decrement_ns_lock_2(void)
62{
63 TRY_SFN(tfm_core_test_sfn, CORE_TEST_ID_BLOCK, 0x2, 0x2, 0x2);
64}
65/**
66 * \brief Test definition for the RTX - TFM integration tests
67 * scenarios
68 */
69enum test_type {
70 TEST_TYPE_1 = 1, /*!< Sequential test: single task using the NS lock to access TFM */
71 TEST_TYPE_2, /*!< Priority test: high priority tries to preempt TFM, gets delayed */
72 TEST_TYPE_3, /*!< Priority inversion: classical scenario with high priority task
73 waiting on lower priority task undefinitely if NS lock is configured
74 without priority inheritance */
75 TEST_TYPE_4, /*!< non-NS lock: like sequential, but doesn't use any NS lock mechanism */
76 TEST_TYPE_5 /*!< non-NS lock, core locked: high priority tries to overcome the NS lock
77 but finds TFM core locked by lower priority task and fails */
78};
79
80static const osThreadAttr_t tattr_seq = {
81 .name = "seq_task",
82 .stack_size = 1024U,
83 .attr_bits = osThreadJoinable,
84 .tz_module = 1,
85};
86static const osThreadAttr_t tattr_mid = {
87 .name = "mid_task",
88 .stack_size = 512U,
89 .attr_bits = osThreadJoinable,
90 .tz_module = 0,
91 .priority = osPriorityAboveNormal
92};
93static const osThreadAttr_t tattr_pri = {
94 .name = "pri_task",
95 .stack_size = 1024U,
96 .attr_bits = osThreadJoinable,
97 .tz_module = 1,
98 .priority = osPriorityHigh
99};
100
101/**
102 * \brief Mutex id, NS lock
103 */
104static osMutexId_t mutex_id;
105
106/**
107 * \brief Mutex properties, NS lock
108 */
109static const osMutexAttr_t mattr_ns_lock = {
110 .name = "ns_lock",
111 //.attr_bits = osMutexPrioInherit
112};
113
114/**
115 * \brief SVC dispatcher
116 */
117__attribute__((always_inline)) __STATIC_INLINE void svc_dispatch(enum tfm_svc_num svc_num)
118{
119 switch (svc_num) {
120 case SVC_SECURE_DECREMENT_NS_LOCK_1:
121 SVC(SVC_SECURE_DECREMENT_NS_LOCK_1);
122 break;
123 case SVC_SECURE_DECREMENT_NS_LOCK_2:
124 SVC(SVC_SECURE_DECREMENT_NS_LOCK_2);
125 break;
126 default:
127 break;
128 }
129}
130
131/**
132 * \brief tfm_service_request
133 *
134 * \details This function is used to request a TFM
135 * service in handler mode, using SVC.
136 * Optionally uses the NS lock
137 */
138static void tfm_service_request(enum tfm_svc_num svc_num, bool use_ns_lock)
139{
140 osStatus_t result;
141
142 char buffer[80];
143
144#define LOG_MSG_THREAD(MSG_THREAD) \
145 do { \
146 sprintf(buffer,"%s [%s]", MSG_THREAD, osThreadGetName(osThreadGetId())); \
147 LOG_MSG(buffer); \
148 } \
149 while(0)
150
151 LOG_MSG_THREAD("Trying to acquire the TFM core from NS");
152
153 if (use_ns_lock) {
154 result = osMutexAcquire(mutex_id,0);
155 if (result == osOK) {
156 LOG_MSG_THREAD("NS Lock: acquired");
157 svc_dispatch(svc_num);
158 LOG_MSG_THREAD("NS Lock: releasing...");
159 osMutexRelease(mutex_id);
160 }
161 else {
162 LOG_MSG_THREAD("Failed to acquire the NS lock");
163
164 osMutexAcquire(mutex_id,osWaitForever);
165 LOG_MSG_THREAD("NS Lock: acquired");
166 svc_dispatch(svc_num);
167 LOG_MSG_THREAD("NS Lock: releasing...");
168 osMutexRelease(mutex_id);
169 }
170 }
171 else {
172 svc_dispatch(svc_num);
173 }
174}
175
176/**
177 * \brief Non-blocking test thread
178 *
179 */
180__attribute__((noreturn))
181static void mid_task(void *argument)
182{
183 osThreadId_t thread_id_pri;
184 osThreadState_t thread_pri_state;
185 uint32_t idx;
186
187 thread_id_pri = *((osThreadId_t *)argument);
188
189 /* go to sleep */
190 osDelay(100U);
191
192 thread_pri_state = osThreadGetState(thread_id_pri);
193
194 if (thread_pri_state == osThreadBlocked) {
195 LOG_MSG("Running [mid_task] while [pri_task] is blocked");
196 }
197 else if (thread_pri_state == osThreadTerminated) {
198 LOG_MSG("Running [mid_task] while [pri_task] is terminated");
199 }
200 else {
201 LOG_MSG("Running [mid_task]");
202 }
203
204 /* Do non TFM related, non blocking, operations */
205 for (idx=0; idx<0x3ffffff; idx++) {
206 }
207
208 LOG_MSG("Exiting [mid_task]");
209
210 osThreadExit();
211}
212
213/**
214 * \brief Priority test thread
215 *
216 */
217__attribute__((noreturn))
218static void pri_task(void *argument)
219{
220 /* go to sleep */
221 osDelay(100U);
222
223 /* After wake up, try to get hold of the NS lock */
224 tfm_service_request(SVC_SECURE_DECREMENT_NS_LOCK_2, *((bool *)argument));
225
226 osThreadExit();
227}
228
229/**
230 * \brief Sequential test thread
231 *
232 */
233__attribute__((noreturn))
234static void seq_task(void *argument)
235{
236 osThreadId_t thread_id, thread_id_mid;
237 bool use_ns_lock, use_ns_lock_pri;
238 enum test_type test_type;
239
240 test_type = *((enum test_type *)argument);
241
242 if (test_type == TEST_TYPE_1) {
243 LOG_MSG("Scenario 1 - Sequential");
244 use_ns_lock = true;
245 }
246 else if (test_type == TEST_TYPE_2) {
247 LOG_MSG("Scenario 2 - Priority");
248 use_ns_lock = true;
249 use_ns_lock_pri = true;
250 thread_id = osThreadNew(pri_task, &use_ns_lock_pri, &tattr_pri);
251 }
252 else if (test_type == TEST_TYPE_3) {
253 LOG_MSG("Scenario 3 - Priority inversion");
254 use_ns_lock = true;
255 use_ns_lock_pri = true;
256 thread_id = osThreadNew(pri_task, &use_ns_lock_pri, &tattr_pri);
257 thread_id_mid = osThreadNew(mid_task, &thread_id, &tattr_mid);
258 }
259 else if (test_type == TEST_TYPE_4) {
260 LOG_MSG("Scenario 4 - non-NS lock");
261 use_ns_lock = false;
262 }
263 else if (test_type == TEST_TYPE_5) {
264 LOG_MSG("Scenario 5 - non-NS lock, core locked");
265 use_ns_lock = true;
266 use_ns_lock_pri = false;
267 thread_id = osThreadNew(pri_task, &use_ns_lock_pri, &tattr_pri);
268 }
269 else {
270 LOG_MSG("Scenario not supported");
271 osThreadExit();
272 }
273
274 /* Try to acquire the NS lock */
275 tfm_service_request(SVC_SECURE_DECREMENT_NS_LOCK_1, use_ns_lock);
276
277 if (test_type == TEST_TYPE_1) {
278 LOG_MSG("Scenario 1 - test finished\n");
279 }
280 else if (test_type == TEST_TYPE_2) {
281 osThreadJoin(thread_id);
282 LOG_MSG("Scenario 2 - test finished\n");
283 }
284 else if (test_type == TEST_TYPE_3) {
285 osThreadJoin(thread_id);
286 osThreadJoin(thread_id_mid);
287 LOG_MSG("Scenario 3 - test finished\n");
288 }
289 else if (test_type == TEST_TYPE_4) {
290 LOG_MSG("Scenario 4 - test finished\n");
291 }
292 else if (test_type == TEST_TYPE_5) {
293 osThreadJoin(thread_id);
294 LOG_MSG("Scenario 5 - test finished\n");
295 }
296
297 osThreadExit();
298}
299
300/**
301 * \brief Execute the interactive tets cases
302 *
303 */
304void execute_ns_interactive_tests(void)
305{
306 uint8_t idx;
307
308 osThreadId_t thread_id;
309
310 /* Test type list */
311 enum test_type test_type[] = {TEST_TYPE_1, TEST_TYPE_2, TEST_TYPE_3, TEST_TYPE_4, TEST_TYPE_5};
312
313 /* Create the NS lock -- shared among testing scenarios */
314 mutex_id = osMutexNew(&mattr_ns_lock);
315
316 /* Loop in the test list */
317 for (idx=0; idx<sizeof(test_type); idx++) {
318 /* Spawn the main thread */
319 thread_id = osThreadNew(seq_task, &test_type[idx], &tattr_seq);
320
321 /* Wait for it to finish before moving to the next scenario */
322 osThreadJoin(thread_id);
323 }
324}
325#endif /* CORE_TEST_INTERACTIVE */
326
327#ifdef TEST_FRAMEWORK_NS
328/**
329 * \brief Services test thread
330 *
331 */
332__attribute__((noreturn))
333void test_app(void *argument)
334{
335 UNUSED_VARIABLE(argument);
336 start_integ_test();
337 /* End of test */
338 for (;;) {
339 }
340}
341#endif /* TEST_FRAMEWORK_NS */