TF-M Reference Manual  1.2.0
TrustedFirmware-M
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
core_ns_interactive_testsuite.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017-2020, Arm Limited. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "core_ns_tests.h"
9 #include "tfm_api.h"
10 #include "cmsis_os2.h"
11 #include "tfm_nspm_api.h"
12 #include "tfm_veneers.h"
13 #include "core_test_api.h"
14 #include "core_test_defs.h"
15 
16 #include <stdio.h>
17 #include <string.h>
18 #include <stdbool.h>
19 
20 #ifdef TFM_PSA_API
21 #include "psa_manifest/sid.h"
22 #endif
23 
24 #ifdef TEST_FRAMEWORK_S
25 #include \
26  "tfm_secure_client_service_api.h"
27 #endif
28 
29 #define TRY_SFN(fn, ...) \
30  do { \
31  enum tfm_status_e res = (enum tfm_status_e) fn(__VA_ARGS__); \
32  switch(res) { \
33  case TFM_SUCCESS: \
34  TEST_LOG("Secure call to " #fn "(" #__VA_ARGS__") successful!");\
35  break; \
36  case TFM_ERROR_SECURE_DOMAIN_LOCKED: \
37  TEST_LOG("Secure call to " #fn "(" #__VA_ARGS__") failed, " \
38  "S domain locked!");\
39  break; \
40  default: \
41  TEST_LOG("Secure call to " #fn "(" #__VA_ARGS__") failed, " \
42  "generic!");\
43  } \
44  } while(0)
45 
46 /* Define test suite for core interactive tests */
47 /* List of tests */
48 static void tfm_core_test_2001(struct test_result_t *ret);
49 
50 static struct test_t core_tests[] = {
51  {&tfm_core_test_2001, "TFM_CORE_TEST_2001",
52  "Interactive tests", {TEST_PASSED} },
53 };
54 
56 {
57  uint32_t list_size;
58 
59  list_size = (sizeof(core_tests) / sizeof(core_tests[0]));
60 
61  set_testsuite("Core non-secure interactive tests (TFM_CORE_TEST_2XXX)",
62  core_tests, list_size, p_test_suite);
63 }
64 
65 static void execute_ns_interactive_tests(void);
66 
70 static void tfm_core_test_2001(struct test_result_t *ret)
71 {
72  execute_ns_interactive_tests();
73 
74  ret->val = TEST_PASSED;
75 }
76 
77 #ifdef TFM_PSA_API
78 static psa_status_t psa_test_common(uint32_t sid, uint32_t version,
79  const psa_invec *in_vecs, size_t in_len,
80  psa_outvec *out_vecs, size_t out_len)
81 {
82  psa_handle_t handle;
83  psa_status_t status;
84 
85  handle = psa_connect(sid, version);
86  if (handle <= 0) {
88  }
89 
90  status = psa_call(handle, PSA_IPC_CALL, in_vecs, in_len, out_vecs, out_len);
91  if (status < 0) {
93  }
94 
95  psa_close(handle);
96  return status;
97 }
98 #endif /* TFM_PSA_API */
99 
105 {
106 #ifndef TFM_PSA_API
107  uint32_t testcase_id = CORE_TEST_ID_BLOCK;
108  psa_invec in_vec = {&testcase_id, sizeof(testcase_id)};
109 
110  TRY_SFN(tfm_spm_core_test_sfn_veneer, &in_vec, 1, NULL, 0);
111 #else
112  psa_status_t err;
113 
114  err = psa_test_common(SPM_CORE_TEST_BLOCK_SID,
116  NULL, 0, NULL, 0);
117  if (err != PSA_SUCCESS) {
118  TEST_LOG("Secure call to sfn block failed, generic!");
119  }
120 #endif
121 }
122 
128 {
129 #ifndef TFM_PSA_API
130  uint32_t testcase_id = CORE_TEST_ID_BLOCK;
131  psa_invec in_vec = {&testcase_id, sizeof(testcase_id)};
132 
133  TRY_SFN(tfm_spm_core_test_sfn_veneer, &in_vec, 1, NULL, 0);
134 #else
135  psa_status_t err;
136 
137  err = psa_test_common(SPM_CORE_TEST_BLOCK_SID,
139  NULL, 0, NULL, 0);
140  if (err != PSA_SUCCESS) {
141  TEST_LOG("Secure call to sfn block failed, generic!");
142  }
143 #endif
144 }
149 enum test_type {
167 };
168 
169 static const osThreadAttr_t tattr_seq = {
170  .name = "seq_task",
171  .stack_size = 1024U,
172  .attr_bits = osThreadJoinable,
173  .tz_module = 1,
174 };
175 static const osThreadAttr_t tattr_mid = {
176  .name = "mid_task",
177  .stack_size = 512U,
178  .attr_bits = osThreadJoinable,
179  .tz_module = 0,
180  .priority = osPriorityAboveNormal
181 };
182 static const osThreadAttr_t tattr_pri = {
183  .name = "pri_task",
184  .stack_size = 1024U,
185  .attr_bits = osThreadJoinable,
186  .tz_module = 1,
187  .priority = osPriorityHigh
188 };
189 
193 static osMutexId_t mutex_id;
194 
198 static const osMutexAttr_t mattr_ns_lock = {
199  .name = "ns_lock",
200  //.attr_bits = osMutexPrioInherit
201 };
202 
209 {
211  uint32_t timeout;
212 };
213 
221 static void tfm_service_request(void(*fn)(void),
222  struct tfm_ns_lock_options *ns_lock_options_p)
223 {
224  osStatus_t result;
225 
226  char buffer[80];
227 
228 #define LOG_MSG_THREAD(MSG_THREAD) \
229  do { \
230  sprintf(buffer,"%s [%s]", MSG_THREAD, osThreadGetName(osThreadGetId())); \
231  TEST_LOG(buffer); \
232  } \
233  while(0)
234 
235  LOG_MSG_THREAD("Trying to acquire the TFM core from NS");
236 
237  if (ns_lock_options_p->use_ns_lock) {
238  result = osMutexAcquire(mutex_id,0);
239  if (result == osOK) {
240  LOG_MSG_THREAD("NS Lock: acquired");
241  /* Add a delay here just to let the pri_task try to
242  * acquire the NS lock before seq_task enters secure world
243  */
244  if (!strcmp(osThreadGetName(osThreadGetId()),"seq_task")) {
245  osDelay(100U);
246  }
247  fn();
248  LOG_MSG_THREAD("NS Lock: releasing...");
249  osMutexRelease(mutex_id);
250  } else {
251 
252  if (ns_lock_options_p->timeout == osWaitForever) {
253  LOG_MSG_THREAD("Failed to acquire NS lock, keep waiting");
254  } else {
255  LOG_MSG_THREAD("Failed to acquire NS lock, wait with timeout");
256  }
257 
258  result = osMutexAcquire(mutex_id,ns_lock_options_p->timeout);
259  if (result == osOK) {
260  LOG_MSG_THREAD("NS Lock: acquired");
261  fn();
262  LOG_MSG_THREAD("NS Lock: releasing...");
263  osMutexRelease(mutex_id);
264  } else if (result == osErrorTimeout) {
265  LOG_MSG_THREAD("NS Lock: failed to acquire, timeout expired");
266  } else {
267  LOG_MSG_THREAD("NS Lock: unexpected failure trying to acquire");
268  }
269  }
270  } else {
271  /* Add a delay here to let the seq_task (which always uses the NS lock)
272  * enter secure world before the pri_task (which can try to overcome the
273  * NS lock in test scenario 5)
274  */
275  if (!strcmp(osThreadGetName(osThreadGetId()),"pri_task")) {
276  osDelay(100U);
277  }
278  fn();
279  }
280 }
281 
286 __attribute__((noreturn))
287 static void mid_task(void *argument)
288 {
289  osThreadId_t thread_id_pri;
290  osThreadState_t thread_pri_state;
291  uint32_t idx;
292 
293 #ifdef TFM_NS_CLIENT_IDENTIFICATION
295 #endif /* TFM_NS_CLIENT_IDENTIFICATION */
296 
297  thread_id_pri = *((osThreadId_t *)argument);
298 
299  /* go to sleep */
300  osDelay(100U);
301 
302  thread_pri_state = osThreadGetState(thread_id_pri);
303 
304  if (thread_pri_state == osThreadBlocked) {
305  TEST_LOG("Running [mid_task] while [pri_task] is blocked");
306  } else if (thread_pri_state == osThreadTerminated) {
307  TEST_LOG("Running [mid_task] while [pri_task] is terminated");
308  } else {
309  TEST_LOG("Running [mid_task]");
310  }
311 
312  /* Do non TFM related, non blocking, operations */
313  for (idx=0; idx<0x3ffffff; idx++) {
314  }
315 
316  TEST_LOG("Exiting [mid_task]");
317 
318  osThreadExit();
319 }
320 
325 __attribute__((noreturn))
326 static void pri_task(void *argument)
327 {
328 #ifdef TFM_NS_CLIENT_IDENTIFICATION
330 #endif /* TFM_NS_CLIENT_IDENTIFICATION */
331 
332  /* go to sleep */
333  osDelay(100U);
334 
335  /* After wake up, try to get hold of the NS lock */
336  tfm_service_request(secure_decrement_ns_lock_2,
337  (struct tfm_ns_lock_options *)argument);
338 
339  osThreadExit();
340 }
341 
346 __attribute__((noreturn))
347 static void seq_task(void *argument)
348 {
349  osThreadId_t thread_id, thread_id_mid;
350  enum test_type test_type;
351 
352  /* By default, use NS lock and wait forever if busy, i.e. until unblocked */
353  struct tfm_ns_lock_options ns_lock_opt =
354  {.use_ns_lock=true, .timeout=osWaitForever};
355  struct tfm_ns_lock_options ns_lock_opt_pri =
356  {.use_ns_lock=true, .timeout=osWaitForever};
357 
358 #ifdef TFM_NS_CLIENT_IDENTIFICATION
360 #endif /* TFM_NS_CLIENT_IDENTIFICATION */
361 
362  test_type = *((enum test_type *)argument);
363 
364  if (test_type == TEST_TYPE_1) {
365  TEST_LOG("Scenario 1 - Sequential");
366  } else if (test_type == TEST_TYPE_2) {
367  TEST_LOG("Scenario 2 - Priority");
368  thread_id = osThreadNew(pri_task, &ns_lock_opt_pri, &tattr_pri);
369  } else if (test_type == TEST_TYPE_3) {
370  TEST_LOG("Scenario 3 - Priority inversion");
371  thread_id = osThreadNew(pri_task, &ns_lock_opt_pri, &tattr_pri);
372  thread_id_mid = osThreadNew(mid_task, &thread_id, &tattr_mid);
373  } else if (test_type == TEST_TYPE_4) {
374  TEST_LOG("Scenario 4 - non-NS lock");
375  ns_lock_opt.use_ns_lock = false;
376  } else if (test_type == TEST_TYPE_5) {
377  TEST_LOG("Scenario 5 - non-NS lock, core locked");
378  ns_lock_opt_pri.use_ns_lock = false;
379  thread_id = osThreadNew(pri_task, &ns_lock_opt_pri, &tattr_pri);
380  } else if (test_type == TEST_TYPE_6) {
381  TEST_LOG("Scenario 6 - Core prioritization effects on NS world");
382  ns_lock_opt_pri.timeout = 0x10000; /* timed_wait for NS lock */
383  thread_id = osThreadNew(pri_task, &ns_lock_opt_pri, &tattr_pri);
384  } else {
385  TEST_LOG("Scenario not supported");
386  osThreadExit();
387  }
388 
389  /* Try to acquire the NS lock */
390  tfm_service_request(secure_decrement_ns_lock_1, &ns_lock_opt);
391 
392  if (test_type == TEST_TYPE_1) {
393  TEST_LOG("Scenario 1 - test finished\n");
394  } else if (test_type == TEST_TYPE_2) {
395  osThreadJoin(thread_id);
396  TEST_LOG("Scenario 2 - test finished\n");
397  } else if (test_type == TEST_TYPE_3) {
398  osThreadJoin(thread_id);
399  osThreadJoin(thread_id_mid);
400  TEST_LOG("Scenario 3 - test finished\n");
401  } else if (test_type == TEST_TYPE_4) {
402  TEST_LOG("Scenario 4 - test finished\n");
403  } else if (test_type == TEST_TYPE_5) {
404  osThreadJoin(thread_id);
405  TEST_LOG("Scenario 5 - test finished\n");
406  } else if (test_type == TEST_TYPE_6) {
407  osThreadJoin(thread_id);
408  TEST_LOG("Scenario 6 - test finished\n");
409  }
410 
411  osThreadExit();
412 }
413 
418 static void execute_ns_interactive_tests(void)
419 {
420  uint8_t idx;
421 
422  osThreadId_t thread_id;
423 
424  /* Test type list */
425  enum test_type test_type[] = {TEST_TYPE_1, TEST_TYPE_2, TEST_TYPE_3,
427 
428  /* Create the NS lock -- shared among testing scenarios */
429  mutex_id = osMutexNew(&mattr_ns_lock);
430 
431  /* Loop in the test list */
432  for (idx=0; idx<sizeof(test_type); idx++) {
433  /* Spawn the main thread */
434  thread_id = osThreadNew(seq_task, &test_type[idx], &tattr_seq);
435 
436  /* Wait for it to finish before moving to the next scenario */
437  osThreadJoin(thread_id);
438  }
439 }
uint32_t tfm_nspm_register_client_id(void)
Reports the client ID of this task to TF-M.
#define PSA_SUCCESS
Definition: crypto_values.h:35
#define SPM_CORE_TEST_BLOCK_SID
Definition: sid.h:76
enum test_suite_err_t set_testsuite(const char *name, struct test_t *test_list, uint32_t size, struct test_suite_t *p_ts)
Sets test suite parameters.
#define CORE_TEST_ID_BLOCK
void psa_close(psa_handle_t handle)
Close a connection to an RoT Service.
Definition: psa_client.c:63
psa_handle_t psa_connect(uint32_t sid, uint32_t version)
Connect to an RoT Service by its SID.
Definition: psa_client.c:30
#define TRY_SFN(fn,...)
test_type
Test definition for the RTX - TFM integration tests scenarios.
#define SPM_CORE_TEST_BLOCK_VERSION
Definition: sid.h:77
struct test_result_t ret
void secure_decrement_ns_lock_1(void)
secure_decrement_ns_lock_1
void register_testsuite_ns_core_interactive(struct test_suite_t *p_test_suite)
Register testsuite for the core interactive tests.
int32_t psa_handle_t
Definition: client.h:61
#define TEST_LOG(...)
enum test_status_t val
void secure_decrement_ns_lock_2(void)
secure_decrement_ns_lock_2
#define PSA_IPC_CALL
Definition: client.h:59
int32_t psa_status_t
Function return status.
Definition: crypto_types.h:43
psa_status_t psa_call(psa_handle_t handle, int32_t type, const psa_invec *in_vec, size_t in_len, psa_outvec *out_vec, size_t out_len)
Call an RoT Service on an established connection.
Definition: psa_client.c:47
#define LOG_MSG_THREAD(MSG_THREAD)