blob: 2d0180948eea3054216a1e8adee141d134c950f2 [file] [log] [blame]
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +00001/*
Mate Toth-Pal5c047152019-02-28 11:07:20 +01002 * Copyright (c) 2017-2019, Arm Limited. All rights reserved.
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +00003 *
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
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000013#include "tfm_api.h"
14#include "cmsis_os2.h"
Mate Toth-Pal3956a8a2018-08-03 17:18:47 +020015#include "tfm_nspm_api.h"
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000016
17#include "tfm_integ_test.h"
Tamas Banc2074a72018-08-14 10:23:12 +010018#include "test/framework/test_framework_integ_test.h"
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000019
Ben Davis6d7256b2018-04-18 14:16:53 +010020#ifdef TEST_FRAMEWORK_S
21#include \
22 "test/test_services/tfm_secure_client_service/tfm_secure_client_service_api.h"
23#endif
24
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000025#ifdef CORE_TEST_INTERACTIVE
26#include "test/test_services/tfm_core_test/core_test_defs.h"
Mate Toth-Pal5c047152019-02-28 11:07:20 +010027#include "tfm_veneers.h"
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000028
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: \
Antonio de Angelis04bf6592018-02-26 11:57:36 +000034 LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") successful!");\
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000035 break; \
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000036 case TFM_ERROR_SECURE_DOMAIN_LOCKED: \
Antonio de Angelis04bf6592018-02-26 11:57:36 +000037 LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") failed, " \
38 "S domain locked!");\
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000039 break; \
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000040 default: \
Antonio de Angelis04bf6592018-02-26 11:57:36 +000041 LOG_MSG("Secure call to " #fn "(" #__VA_ARGS__") failed, " \
42 "generic!");\
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000043 } \
44 } while(0)
Mate Toth-Pal813e9d12019-01-17 15:51:29 +010045
46#ifdef TFM_PSA_API
47static psa_status_t psa_test_common(uint32_t sid, uint32_t minor_version,
48 const psa_invec *in_vecs, size_t in_len,
49 psa_outvec *out_vecs, size_t out_len)
50{
51 psa_handle_t handle;
52 psa_status_t status;
53
54 handle = psa_connect(sid, minor_version);
55 if (handle <= 0) {
56 return CORE_TEST_ERRNO_INVALID_PARAMETER;
57 }
58
59 status = psa_call(handle, in_vecs, in_len, out_vecs, out_len);
60 if (status < 0) {
61 status = CORE_TEST_ERRNO_UNEXPECTED_CORE_BEHAVIOUR;
62 }
63
64 psa_close(handle);
65 return status;
66}
67#endif /* TFM_PSA_API */
68
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000069/**
Mate Toth-Pal1379e152018-07-30 17:38:29 +020070 * \brief secure_decrement_ns_lock_1
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000071 *
72 */
Mate Toth-Pal1379e152018-07-30 17:38:29 +020073void secure_decrement_ns_lock_1(void)
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000074{
Mate Toth-Pal813e9d12019-01-17 15:51:29 +010075#ifndef TFM_PSA_API
Mate Toth-Pal5c047152019-02-28 11:07:20 +010076 uint32_t testcase_id = CORE_TEST_ID_BLOCK;
77 psa_invec in_vec = {&testcase_id, sizeof(testcase_id)};
78
79 TRY_SFN(tfm_spm_core_test_sfn_veneer, &in_vec, 1, NULL, 0);
Mate Toth-Pal813e9d12019-01-17 15:51:29 +010080#else
81 psa_status_t err;
82
83 err = psa_test_common(SPM_CORE_TEST_BLOCK_SID,
84 SPM_CORE_TEST_BLOCK_MIN_VER,
85 NULL, 0, NULL, 0);
86 if (err != PSA_SUCCESS) {
87 LOG_MSG("Secure call to sfn block failed, generic!");
88 }
89#endif
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000090}
91
92/**
Mate Toth-Pal1379e152018-07-30 17:38:29 +020093 * \brief secure_decrement_ns_lock_2
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000094 *
95 */
Mate Toth-Pal1379e152018-07-30 17:38:29 +020096void secure_decrement_ns_lock_2(void)
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +000097{
Mate Toth-Pal813e9d12019-01-17 15:51:29 +010098#ifndef TFM_PSA_API
Mate Toth-Pal5c047152019-02-28 11:07:20 +010099 uint32_t testcase_id = CORE_TEST_ID_BLOCK;
100 psa_invec in_vec = {&testcase_id, sizeof(testcase_id)};
101
102 TRY_SFN(tfm_spm_core_test_sfn_veneer, &in_vec, 1, NULL, 0);
Mate Toth-Pal813e9d12019-01-17 15:51:29 +0100103#else
104 psa_status_t err;
105
106 err = psa_test_common(SPM_CORE_TEST_BLOCK_SID,
107 SPM_CORE_TEST_BLOCK_MIN_VER,
108 NULL, 0, NULL, 0);
109 if (err != PSA_SUCCESS) {
110 LOG_MSG("Secure call to sfn block failed, generic!");
111 }
112#endif
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000113}
114/**
115 * \brief Test definition for the RTX - TFM integration tests
116 * scenarios
117 */
118enum test_type {
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000119 TEST_TYPE_1 = 1, /*!< Sequential test: single task using the NS lock to
120 access TFM */
121 TEST_TYPE_2, /*!< Priority test: high priority tries to preempt TFM,
122 gets delayed */
123 TEST_TYPE_3, /*!< Priority inversion: classical scenario with high
124 priority task waiting on lower priority task
125 undefinitely if NS lock is configured without priority
126 inheritance */
127 TEST_TYPE_4, /*!< non-NS lock: like sequential, but doesn't use any NS
128 lock mechanism */
129 TEST_TYPE_5, /*!< non-NS lock, core locked: high priority tries to
130 overcome the NS lock but finds TFM core locked by
131 lower priority task and fails */
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000132 TEST_TYPE_6 /*!< Like TEST_TYPE_2, but the high priority task has now a
133 timeout to acquire the NS lock. The timeout will
134 expire only if TFM Core is built with the
Miklos Balintace4c3f2018-07-30 12:31:15 +0200135 de-prioritization disabled */
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000136};
137
138static const osThreadAttr_t tattr_seq = {
139 .name = "seq_task",
140 .stack_size = 1024U,
141 .attr_bits = osThreadJoinable,
142 .tz_module = 1,
143};
144static const osThreadAttr_t tattr_mid = {
145 .name = "mid_task",
146 .stack_size = 512U,
147 .attr_bits = osThreadJoinable,
148 .tz_module = 0,
149 .priority = osPriorityAboveNormal
150};
151static const osThreadAttr_t tattr_pri = {
152 .name = "pri_task",
153 .stack_size = 1024U,
154 .attr_bits = osThreadJoinable,
155 .tz_module = 1,
156 .priority = osPriorityHigh
157};
158
159/**
160 * \brief Mutex id, NS lock
161 */
162static osMutexId_t mutex_id;
163
164/**
165 * \brief Mutex properties, NS lock
166 */
167static const osMutexAttr_t mattr_ns_lock = {
168 .name = "ns_lock",
169 //.attr_bits = osMutexPrioInherit
170};
171
172/**
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000173 * \brief TFM NS lock options
174 *
175 * \details Options used while acquiring the NS lock
176 */
177struct tfm_ns_lock_options
178{
179 bool use_ns_lock;
180 uint32_t timeout;
181};
182
183/**
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000184 * \brief tfm_service_request
185 *
Mate Toth-Pal1379e152018-07-30 17:38:29 +0200186 * \details This function is used to request a TFM service in thread mode.
187 * Optionally uses the NS lock and specifies a timeout for obtaining
188 * the NS lock.
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000189 */
Mate Toth-Pal1379e152018-07-30 17:38:29 +0200190static void tfm_service_request(void(*fn)(void),
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000191 struct tfm_ns_lock_options *ns_lock_options_p)
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000192{
193 osStatus_t result;
194
195 char buffer[80];
196
197#define LOG_MSG_THREAD(MSG_THREAD) \
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000198 do { \
199 sprintf(buffer,"%s [%s]", MSG_THREAD, osThreadGetName(osThreadGetId())); \
200 LOG_MSG(buffer); \
201 } \
202 while(0)
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000203
204 LOG_MSG_THREAD("Trying to acquire the TFM core from NS");
205
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000206 if (ns_lock_options_p->use_ns_lock) {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000207 result = osMutexAcquire(mutex_id,0);
208 if (result == osOK) {
209 LOG_MSG_THREAD("NS Lock: acquired");
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000210 /* Add a delay here just to let the pri_task try to
211 * acquire the NS lock before seq_task enters secure world
212 */
213 if (!strcmp(osThreadGetName(osThreadGetId()),"seq_task")) {
214 osDelay(100U);
215 }
Mate Toth-Pal1379e152018-07-30 17:38:29 +0200216 fn();
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000217 LOG_MSG_THREAD("NS Lock: releasing...");
218 osMutexRelease(mutex_id);
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000219 } else {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000220
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000221 if (ns_lock_options_p->timeout == osWaitForever) {
222 LOG_MSG_THREAD("Failed to acquire NS lock, keep waiting");
223 } else {
224 LOG_MSG_THREAD("Failed to acquire NS lock, wait with timeout");
225 }
226
227 result = osMutexAcquire(mutex_id,ns_lock_options_p->timeout);
228 if (result == osOK) {
229 LOG_MSG_THREAD("NS Lock: acquired");
Mate Toth-Pal1379e152018-07-30 17:38:29 +0200230 fn();
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000231 LOG_MSG_THREAD("NS Lock: releasing...");
232 osMutexRelease(mutex_id);
233 } else if (result == osErrorTimeout) {
234 LOG_MSG_THREAD("NS Lock: failed to acquire, timeout expired");
235 } else {
236 LOG_MSG_THREAD("NS Lock: unexpected failure trying to acquire");
237 }
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000238 }
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000239 } else {
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000240 /* Add a delay here to let the seq_task (which always uses the NS lock)
241 * enter secure world before the pri_task (which can try to overcome the
242 * NS lock in test scenario 5)
243 */
244 if (!strcmp(osThreadGetName(osThreadGetId()),"pri_task")) {
245 osDelay(100U);
246 }
Mate Toth-Pal1379e152018-07-30 17:38:29 +0200247 fn();
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000248 }
249}
250
251/**
252 * \brief Non-blocking test thread
253 *
254 */
255__attribute__((noreturn))
256static void mid_task(void *argument)
257{
258 osThreadId_t thread_id_pri;
259 osThreadState_t thread_pri_state;
260 uint32_t idx;
261
Mate Toth-Pal53136092018-09-19 09:34:01 +0200262#ifdef TFM_NS_CLIENT_IDENTIFICATION
Mate Toth-Pal3956a8a2018-08-03 17:18:47 +0200263 tfm_nspm_register_client_id();
Mate Toth-Pal53136092018-09-19 09:34:01 +0200264#endif /* TFM_NS_CLIENT_IDENTIFICATION */
Mate Toth-Pal3956a8a2018-08-03 17:18:47 +0200265
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000266 thread_id_pri = *((osThreadId_t *)argument);
267
268 /* go to sleep */
269 osDelay(100U);
270
271 thread_pri_state = osThreadGetState(thread_id_pri);
272
273 if (thread_pri_state == osThreadBlocked) {
274 LOG_MSG("Running [mid_task] while [pri_task] is blocked");
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000275 } else if (thread_pri_state == osThreadTerminated) {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000276 LOG_MSG("Running [mid_task] while [pri_task] is terminated");
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000277 } else {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000278 LOG_MSG("Running [mid_task]");
279 }
280
281 /* Do non TFM related, non blocking, operations */
282 for (idx=0; idx<0x3ffffff; idx++) {
283 }
284
285 LOG_MSG("Exiting [mid_task]");
286
287 osThreadExit();
288}
289
290/**
291 * \brief Priority test thread
292 *
293 */
294__attribute__((noreturn))
295static void pri_task(void *argument)
296{
Mate Toth-Pal53136092018-09-19 09:34:01 +0200297#ifdef TFM_NS_CLIENT_IDENTIFICATION
Mate Toth-Pal3956a8a2018-08-03 17:18:47 +0200298 tfm_nspm_register_client_id();
Mate Toth-Pal53136092018-09-19 09:34:01 +0200299#endif /* TFM_NS_CLIENT_IDENTIFICATION */
Mate Toth-Pal3956a8a2018-08-03 17:18:47 +0200300
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000301 /* go to sleep */
302 osDelay(100U);
303
304 /* After wake up, try to get hold of the NS lock */
Mate Toth-Pal1379e152018-07-30 17:38:29 +0200305 tfm_service_request(secure_decrement_ns_lock_2,
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000306 (struct tfm_ns_lock_options *)argument);
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000307
308 osThreadExit();
309}
310
311/**
312 * \brief Sequential test thread
313 *
314 */
315__attribute__((noreturn))
316static void seq_task(void *argument)
317{
318 osThreadId_t thread_id, thread_id_mid;
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000319 enum test_type test_type;
320
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000321 /* By default, use NS lock and wait forever if busy, i.e. until unblocked */
322 struct tfm_ns_lock_options ns_lock_opt =
323 {.use_ns_lock=true, .timeout=osWaitForever};
324 struct tfm_ns_lock_options ns_lock_opt_pri =
325 {.use_ns_lock=true, .timeout=osWaitForever};
326
Mate Toth-Pal53136092018-09-19 09:34:01 +0200327#ifdef TFM_NS_CLIENT_IDENTIFICATION
Mate Toth-Pal3956a8a2018-08-03 17:18:47 +0200328 tfm_nspm_register_client_id();
Mate Toth-Pal53136092018-09-19 09:34:01 +0200329#endif /* TFM_NS_CLIENT_IDENTIFICATION */
Mate Toth-Pal3956a8a2018-08-03 17:18:47 +0200330
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000331 test_type = *((enum test_type *)argument);
332
333 if (test_type == TEST_TYPE_1) {
334 LOG_MSG("Scenario 1 - Sequential");
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000335 } else if (test_type == TEST_TYPE_2) {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000336 LOG_MSG("Scenario 2 - Priority");
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000337 thread_id = osThreadNew(pri_task, &ns_lock_opt_pri, &tattr_pri);
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000338 } else if (test_type == TEST_TYPE_3) {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000339 LOG_MSG("Scenario 3 - Priority inversion");
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000340 thread_id = osThreadNew(pri_task, &ns_lock_opt_pri, &tattr_pri);
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000341 thread_id_mid = osThreadNew(mid_task, &thread_id, &tattr_mid);
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000342 } else if (test_type == TEST_TYPE_4) {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000343 LOG_MSG("Scenario 4 - non-NS lock");
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000344 ns_lock_opt.use_ns_lock = false;
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000345 } else if (test_type == TEST_TYPE_5) {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000346 LOG_MSG("Scenario 5 - non-NS lock, core locked");
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000347 ns_lock_opt_pri.use_ns_lock = false;
348 thread_id = osThreadNew(pri_task, &ns_lock_opt_pri, &tattr_pri);
349 } else if (test_type == TEST_TYPE_6) {
350 LOG_MSG("Scenario 6 - Core prioritization effects on NS world");
351 ns_lock_opt_pri.timeout = 0x10000; /* timed_wait for NS lock */
352 thread_id = osThreadNew(pri_task, &ns_lock_opt_pri, &tattr_pri);
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000353 } else {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000354 LOG_MSG("Scenario not supported");
355 osThreadExit();
356 }
357
358 /* Try to acquire the NS lock */
Mate Toth-Pal1379e152018-07-30 17:38:29 +0200359 tfm_service_request(secure_decrement_ns_lock_1, &ns_lock_opt);
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000360
361 if (test_type == TEST_TYPE_1) {
362 LOG_MSG("Scenario 1 - test finished\n");
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000363 } else if (test_type == TEST_TYPE_2) {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000364 osThreadJoin(thread_id);
365 LOG_MSG("Scenario 2 - test finished\n");
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000366 } else if (test_type == TEST_TYPE_3) {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000367 osThreadJoin(thread_id);
368 osThreadJoin(thread_id_mid);
369 LOG_MSG("Scenario 3 - test finished\n");
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000370 } else if (test_type == TEST_TYPE_4) {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000371 LOG_MSG("Scenario 4 - test finished\n");
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000372 } else if (test_type == TEST_TYPE_5) {
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000373 osThreadJoin(thread_id);
374 LOG_MSG("Scenario 5 - test finished\n");
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000375 } else if (test_type == TEST_TYPE_6) {
376 osThreadJoin(thread_id);
377 LOG_MSG("Scenario 6 - test finished\n");
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000378 }
379
380 osThreadExit();
381}
382
383/**
384 * \brief Execute the interactive tets cases
385 *
386 */
387void execute_ns_interactive_tests(void)
388{
389 uint8_t idx;
390
391 osThreadId_t thread_id;
392
393 /* Test type list */
Antonio de Angelis04bf6592018-02-26 11:57:36 +0000394 enum test_type test_type[] = {TEST_TYPE_1, TEST_TYPE_2, TEST_TYPE_3,
Antonio de Angelis1ea2a132017-12-06 14:36:05 +0000395 TEST_TYPE_4, TEST_TYPE_5, TEST_TYPE_6};
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000396
397 /* Create the NS lock -- shared among testing scenarios */
398 mutex_id = osMutexNew(&mattr_ns_lock);
399
400 /* Loop in the test list */
401 for (idx=0; idx<sizeof(test_type); idx++) {
402 /* Spawn the main thread */
403 thread_id = osThreadNew(seq_task, &test_type[idx], &tattr_seq);
404
405 /* Wait for it to finish before moving to the next scenario */
406 osThreadJoin(thread_id);
407 }
408}
409#endif /* CORE_TEST_INTERACTIVE */
410
Ben Davis6d7256b2018-04-18 14:16:53 +0100411#if defined(TEST_FRAMEWORK_NS) || defined(TEST_FRAMEWORK_S)
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000412/**
413 * \brief Services test thread
414 *
415 */
416__attribute__((noreturn))
417void test_app(void *argument)
418{
419 UNUSED_VARIABLE(argument);
Ben Davis6d7256b2018-04-18 14:16:53 +0100420
421#ifdef TEST_FRAMEWORK_S
422 /* FIXME: The non-secure audit log test currently relies on the fact that
423 * the audit log secure test is run first. However the Non-secure tests
424 * represent simpler and more common test cases which would make more sense
425 * to be run first. Therefore if this dependency is removed the execution
426 * order of these test classes should be reversed. */
427 tfm_secure_client_run_tests();
428#endif
429#ifdef TEST_FRAMEWORK_NS
430 tfm_non_secure_client_run_tests();
431#endif
Antonio de Angelisa54ed7e2017-11-29 13:37:58 +0000432 /* End of test */
433 for (;;) {
434 }
435}
Ben Davis6d7256b2018-04-18 14:16:53 +0100436#endif /* TEST_FRAMEWORK_NS OR TEST_FRAMEWORK_S */