1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <internal/fwk_context.h>
9 #include <internal/fwk_core.h>
10 #include <internal/fwk_module.h>
11
12 #include <fwk_assert.h>
13 #include <fwk_id.h>
14 #include <fwk_list.h>
15 #include <fwk_macros.h>
16 #include <fwk_slist.h>
17 #include <fwk_status.h>
18 #include <fwk_test.h>
19
20 #include <setjmp.h>
21 #include <stdbool.h>
22 #include <stdlib.h>
23
24 static jmp_buf test_context;
25 static struct __fwk_ctx *ctx;
26 static struct fwk_element_ctx fake_element_ctx;
27
28 /* Mock functions */
29 static void *fwk_mm_calloc_val;
30 static int fwk_mm_calloc_return_val;
__wrap_fwk_mm_calloc(size_t num,size_t size)31 void *__wrap_fwk_mm_calloc(size_t num, size_t size)
32 {
33 if (fwk_mm_calloc_return_val) {
34 fwk_mm_calloc_val = (void *)calloc(num, size);
35 return fwk_mm_calloc_val;
36 }
37 return NULL;
38 }
39
40 static struct fwk_module fake_module_desc;
41 static struct fwk_module_context fake_module_ctx;
__wrap_fwk_module_get_ctx(fwk_id_t id)42 struct fwk_module_context *__wrap_fwk_module_get_ctx(fwk_id_t id)
43 {
44 return &fake_module_ctx;
45 }
46
47 bool free_event_queue_break;
48 extern void __real___fwk_slist_push_tail(
49 struct fwk_slist *restrict list,
50 struct fwk_slist_node *restrict node);
__wrap___fwk_slist_push_tail(struct fwk_slist * restrict list,struct fwk_slist_node * restrict new)51 void __wrap___fwk_slist_push_tail(
52 struct fwk_slist *restrict list,
53 struct fwk_slist_node *restrict new)
54 {
55 __real___fwk_slist_push_tail(list, new);
56 if (free_event_queue_break && (list == &(ctx->free_event_queue)))
57 longjmp(test_context, FWK_SUCCESS);
58 }
59
60 static bool is_valid_entity_id_return_val;
__wrap_fwk_module_is_valid_entity_id(fwk_id_t id)61 bool __wrap_fwk_module_is_valid_entity_id(fwk_id_t id)
62 {
63 return is_valid_entity_id_return_val;
64 }
65
66 static bool is_valid_event_id_return_val;
__wrap_fwk_module_is_valid_event_id(fwk_id_t id)67 bool __wrap_fwk_module_is_valid_event_id(fwk_id_t id)
68 {
69 return is_valid_event_id_return_val;
70 }
71
72 static bool is_valid_notification_id_return_val;
__wrap_fwk_module_is_valid_notification_id(fwk_id_t id)73 bool __wrap_fwk_module_is_valid_notification_id(fwk_id_t id)
74 {
75 return is_valid_notification_id_return_val;
76 }
77
__wrap_fwk_module_get_element_ctx(fwk_id_t id)78 struct fwk_element_ctx *__wrap_fwk_module_get_element_ctx(fwk_id_t id)
79 {
80 (void)id;
81 return &fake_element_ctx;
82 }
83
__wrap_fwk_interrupt_global_enable(void)84 int __wrap_fwk_interrupt_global_enable(void)
85 {
86 return FWK_SUCCESS;
87 }
88
__wrap_fwk_interrupt_global_disable(void)89 int __wrap_fwk_interrupt_global_disable(void)
90 {
91 return FWK_SUCCESS;
92 }
93
94 static bool interrupt_get_current_return_val;
__wrap_fwk_is_interrupt_context(void)95 bool __wrap_fwk_is_interrupt_context(void)
96 {
97 return interrupt_get_current_return_val;
98 }
99
100 static const struct fwk_event *processed_event;
process_event(const struct fwk_event * event,struct fwk_event * response_event)101 static int process_event(
102 const struct fwk_event *event,
103 struct fwk_event *response_event)
104 {
105 processed_event = event;
106 return FWK_SUCCESS;
107 }
108
109 static const struct fwk_event *processed_notification;
110
process_notification(const struct fwk_event * event,struct fwk_event * response_event)111 static int process_notification(
112 const struct fwk_event *event,
113 struct fwk_event *response_event)
114 {
115 processed_notification = event;
116 return FWK_SUCCESS;
117 }
118
test_suite_setup(void)119 static int test_suite_setup(void)
120 {
121 ctx = __fwk_get_ctx();
122 fake_module_desc.process_event = process_event;
123 fake_module_desc.process_notification = process_notification;
124 fake_module_ctx.desc = &fake_module_desc;
125 return FWK_SUCCESS;
126 }
127
test_case_setup(void)128 static void test_case_setup(void)
129 {
130 free_event_queue_break = false;
131 is_valid_entity_id_return_val = true;
132 is_valid_event_id_return_val = true;
133 is_valid_notification_id_return_val = true;
134 interrupt_get_current_return_val = false;
135 fwk_mm_calloc_return_val = true;
136 fake_module_desc.process_event = process_event;
137 fake_module_ctx.desc = &fake_module_desc;
138 }
139
test_case_teardown(void)140 static void test_case_teardown(void)
141 {
142 *ctx = (struct __fwk_ctx){};
143 fwk_list_init(&ctx->free_event_queue);
144 fwk_list_init(&ctx->event_queue);
145 fwk_list_init(&ctx->isr_event_queue);
146 }
147
test___fwk_init(void)148 static void test___fwk_init(void)
149 {
150 int result;
151 size_t event_count = 2;
152
153 fwk_mm_calloc_return_val = true;
154
155 /* Insert 2 events in the list */
156 result = __fwk_init(event_count);
157 assert(result == FWK_SUCCESS);
158 assert(
159 ctx->free_event_queue.head ==
160 &(((struct fwk_event *)fwk_mm_calloc_val)->slist_node));
161 assert(
162 ctx->free_event_queue.tail ==
163 &((((struct fwk_event *)(fwk_mm_calloc_val)) + 1)->slist_node));
164 }
165
test___fwk_run_main_loop(void)166 static void test___fwk_run_main_loop(void)
167 {
168 int result;
169 struct fwk_event *free_event, *allocated_event;
170
171 struct fwk_event event1 = {
172 .source_id = FWK_ID_MODULE(0x1),
173 .target_id = FWK_ID_MODULE(0x2),
174 .is_response = false,
175 .response_requested = true,
176 .is_notification = false,
177 .id = FWK_ID_EVENT(0x2, 0x7),
178 };
179
180 struct fwk_event event2 = {
181 .source_id = FWK_ID_MODULE(0x3),
182 .target_id = FWK_ID_MODULE(0x4),
183 .is_response = false,
184 .response_requested = false,
185 .is_notification = true,
186 .id = FWK_ID_NOTIFICATION(0x4, 0x8),
187 };
188
189 struct fwk_event event3 = {
190 .source_id = FWK_ID_MODULE(0x5),
191 .target_id = FWK_ID_MODULE(0x6),
192 .is_response = false,
193 .response_requested = false,
194 .is_notification = false,
195 .id = FWK_ID_EVENT(0x6, 0x9),
196 };
197
198 struct fwk_event notification1 = {
199 .source_id = FWK_ID_MODULE(0x5),
200 .target_id = FWK_ID_MODULE(0x6),
201 .is_response = false,
202 .response_requested = true,
203 .is_notification = true,
204 .id = FWK_ID_NOTIFICATION(0x5, 0x9),
205 };
206
207 result = __fwk_init(1);
208 assert(result == FWK_SUCCESS);
209 free_event_queue_break = true;
210 allocated_event = FWK_LIST_GET(
211 fwk_list_head(&ctx->free_event_queue), struct fwk_event, slist_node);
212
213 __real___fwk_slist_push_tail(&ctx->event_queue, &(event1.slist_node));
214 __real___fwk_slist_push_tail(&ctx->event_queue, &(event2.slist_node));
215 __real___fwk_slist_push_tail(&ctx->isr_event_queue, &(event3.slist_node));
216 __real___fwk_slist_push_tail(
217 &ctx->isr_event_queue, &(notification1.slist_node));
218
219 /* Event1 processing */
220 if (setjmp(test_context) == FWK_SUCCESS)
221 __fwk_run_main_loop();
222 assert(ctx->isr_event_queue.head == &(event3.slist_node));
223 assert(ctx->isr_event_queue.tail == &(notification1.slist_node));
224 assert(ctx->event_queue.head == &(event2.slist_node));
225 assert(ctx->event_queue.tail == &(allocated_event->slist_node));
226
227 free_event = FWK_LIST_GET(
228 fwk_list_pop_head(&ctx->free_event_queue),
229 struct fwk_event,
230 slist_node);
231 assert(fwk_list_is_empty(&ctx->free_event_queue));
232 assert(free_event == &event1);
233 assert(processed_event == &event1);
234 assert(processed_event->is_response == false);
235 assert(processed_event->response_requested == true);
236 assert(processed_event->is_notification == false);
237
238 /* Event2 processing */
239 if (setjmp(test_context) == FWK_SUCCESS)
240 __fwk_run_main_loop();
241 assert(ctx->isr_event_queue.head == &(event3.slist_node));
242 assert(ctx->isr_event_queue.tail == &(notification1.slist_node));
243 assert(ctx->event_queue.head == &(allocated_event->slist_node));
244 assert(ctx->event_queue.tail == &(allocated_event->slist_node));
245
246 free_event = FWK_LIST_GET(
247 fwk_list_pop_head(&ctx->free_event_queue),
248 struct fwk_event,
249 slist_node);
250 assert(fwk_list_is_empty(&ctx->free_event_queue));
251 assert(free_event == &event2);
252 assert(processed_notification == &event2);
253 assert(processed_notification->is_response == false);
254 assert(processed_notification->response_requested == false);
255 assert(processed_notification->is_notification == true);
256
257 /* Response to Event1 processing */
258 if (setjmp(test_context) == FWK_SUCCESS)
259 __fwk_run_main_loop();
260 assert(ctx->isr_event_queue.head == &(event3.slist_node));
261 assert(ctx->isr_event_queue.tail == &(notification1.slist_node));
262 assert(fwk_list_is_empty(&ctx->event_queue));
263
264 free_event = FWK_LIST_GET(
265 fwk_list_pop_head(&ctx->free_event_queue),
266 struct fwk_event,
267 slist_node);
268 assert(free_event == allocated_event);
269 assert(processed_event == allocated_event);
270 assert(processed_event->is_response == true);
271 assert(processed_event->response_requested == false);
272 assert(processed_event->is_notification == false);
273 assert(fwk_id_is_equal(processed_event->source_id, FWK_ID_MODULE(0x2)));
274 assert(fwk_id_is_equal(processed_event->target_id, FWK_ID_MODULE(0x1)));
275 assert(fwk_id_is_equal(processed_event->id, FWK_ID_EVENT(0x2, 0x7)));
276
277 /* Extract ISR Event3 and process it */
278 if (setjmp(test_context) == FWK_SUCCESS)
279 __fwk_run_main_loop();
280 assert(ctx->isr_event_queue.head == &(notification1.slist_node));
281 assert(ctx->isr_event_queue.tail == &(notification1.slist_node));
282 assert(fwk_list_is_empty(&ctx->event_queue));
283
284 free_event = FWK_LIST_GET(
285 fwk_list_pop_head(&ctx->free_event_queue),
286 struct fwk_event,
287 slist_node);
288 assert(free_event == &event3);
289 assert(processed_event == &event3);
290 assert(processed_event->is_response == false);
291 assert(processed_event->response_requested == false);
292 assert(processed_event->is_notification == false);
293
294 /* Extract ISR Notification1 and process it */
295 free_event_queue_break = false;
296 fwk_list_push_tail(&ctx->free_event_queue, &(allocated_event->slist_node));
297 free_event_queue_break = true;
298 if (setjmp(test_context) == FWK_SUCCESS)
299 __fwk_run_main_loop();
300 assert(fwk_list_is_empty(&ctx->isr_event_queue));
301 assert(ctx->event_queue.head == &(allocated_event->slist_node));
302 assert(ctx->event_queue.tail == &(allocated_event->slist_node));
303
304 free_event = FWK_LIST_GET(
305 fwk_list_pop_head(&ctx->free_event_queue),
306 struct fwk_event,
307 slist_node);
308 assert(free_event == ¬ification1);
309 assert(processed_notification == ¬ification1);
310 assert(processed_notification->is_response == false);
311 assert(processed_notification->response_requested == true);
312 assert(processed_notification->is_notification == true);
313
314 /* Process response to Notification1 */
315 if (setjmp(test_context) == FWK_SUCCESS)
316 __fwk_run_main_loop();
317 assert(fwk_list_is_empty(&ctx->isr_event_queue));
318 assert(fwk_list_is_empty(&ctx->event_queue));
319
320 free_event = FWK_LIST_GET(
321 fwk_list_pop_head(&ctx->free_event_queue),
322 struct fwk_event,
323 slist_node);
324 assert(free_event == allocated_event);
325 assert(processed_notification == allocated_event);
326 assert(processed_notification->is_response == true);
327 assert(processed_notification->response_requested == false);
328 assert(processed_notification->is_notification == true);
329 assert(
330 fwk_id_is_equal(processed_notification->source_id, FWK_ID_MODULE(0x6)));
331 assert(
332 fwk_id_is_equal(processed_notification->target_id, FWK_ID_MODULE(0x5)));
333 assert(fwk_id_is_equal(
334 processed_notification->id, FWK_ID_NOTIFICATION(0x5, 0x9)));
335 }
336
test_fwk_put_event(void)337 static void test_fwk_put_event(void)
338 {
339 int result;
340 struct fwk_event *result_event;
341
342 struct fwk_event event1 = {
343 .source_id = FWK_ID_MODULE(0x1),
344 .target_id = FWK_ID_MODULE(0x2),
345 .is_response = false,
346 .response_requested = true,
347 .id = FWK_ID_EVENT(0x2, 7),
348 };
349
350 struct fwk_event event2 = {
351 .source_id = FWK_ID_MODULE(0x3),
352 .target_id = FWK_ID_MODULE(0x4),
353 .is_response = true,
354 .response_requested = false,
355 };
356
357 /* Framework core not initialized */
358 result = fwk_put_event(&event2);
359 assert(result == FWK_E_INIT);
360
361 result = __fwk_init(2);
362 assert(result == FWK_SUCCESS);
363
364 /* Invalid entity ID */
365 is_valid_entity_id_return_val = false;
366 result = fwk_put_event(&event2);
367 assert(result == FWK_E_PARAM);
368 is_valid_entity_id_return_val = true;
369
370 /* Invalid event ID */
371 is_valid_event_id_return_val = false;
372 result = fwk_put_event(&event2);
373 assert(result == FWK_E_PARAM);
374 is_valid_event_id_return_val = true;
375
376 /* Incompatible target and event identifier */
377 event2.id = FWK_ID_EVENT(0x2, 7);
378 result = fwk_put_event(&event2);
379 assert(result == FWK_E_PARAM);
380
381 result = fwk_put_event(&event1);
382 assert(result == FWK_SUCCESS);
383 result_event = FWK_LIST_GET(
384 fwk_list_pop_head(&ctx->event_queue), struct fwk_event, slist_node);
385 assert(fwk_id_is_equal(result_event->source_id, event1.source_id));
386 assert(fwk_id_is_equal(result_event->target_id, event1.target_id));
387 assert(result_event->is_response == event1.is_response);
388 assert(result_event->response_requested == event1.response_requested);
389 assert(result_event->is_notification == false);
390
391 event2.id = FWK_ID_EVENT(0x3, 7);
392 interrupt_get_current_return_val = true;
393 result = fwk_put_event(&event2);
394 assert(result == FWK_SUCCESS);
395 assert(fwk_list_is_empty(&ctx->free_event_queue));
396 result_event = FWK_LIST_GET(
397 fwk_list_pop_head(&ctx->isr_event_queue), struct fwk_event, slist_node);
398 assert(fwk_id_is_equal(result_event->source_id, event2.source_id));
399 assert(fwk_id_is_equal(result_event->target_id, event2.target_id));
400 assert(result_event->is_response == true);
401 assert(result_event->response_requested == event2.response_requested);
402 assert(result_event->is_notification == false);
403 }
404
test_fwk_put_event_light(void)405 static void test_fwk_put_event_light(void)
406 {
407 int result;
408 struct fwk_event *result_event;
409
410 struct fwk_event_light event1 = {
411 .source_id = FWK_ID_MODULE(0x1),
412 .target_id = FWK_ID_MODULE(0x2),
413 .response_requested = true,
414 .id = FWK_ID_EVENT(0x2, 7),
415 };
416
417 struct fwk_event_light event2 = {
418 .source_id = FWK_ID_MODULE(0x3),
419 .target_id = FWK_ID_MODULE(0x4),
420 .response_requested = false,
421 .id = FWK_ID_EVENT(0x4, 7),
422 };
423
424 /* Framework core not initialized */
425 result = fwk_put_event(&event2);
426 assert(result == FWK_E_INIT);
427
428 result = __fwk_init(2);
429 assert(result == FWK_SUCCESS);
430
431 /* Invalid entity ID */
432 is_valid_entity_id_return_val = false;
433 result = fwk_put_event(&event2);
434 assert(result == FWK_E_PARAM);
435 is_valid_entity_id_return_val = true;
436
437 /* Invalid event ID */
438 is_valid_event_id_return_val = false;
439 result = fwk_put_event(&event2);
440 assert(result == FWK_E_PARAM);
441 is_valid_event_id_return_val = true;
442
443 /* Incompatible target and event identifier */
444 event2.id = FWK_ID_EVENT(0x2, 7);
445 result = fwk_put_event(&event2);
446 assert(result == FWK_E_PARAM);
447
448 /* Valid event id */
449 result = fwk_put_event(&event1);
450 assert(result == FWK_SUCCESS);
451 /* Framework always queue light event by converting in a standard event */
452 result_event = FWK_LIST_GET(
453 fwk_list_pop_head(&ctx->event_queue), struct fwk_event, slist_node);
454 assert(fwk_id_is_equal(result_event->source_id, event1.source_id));
455 assert(fwk_id_is_equal(result_event->target_id, event1.target_id));
456 assert(result_event->is_response == false);
457 assert(result_event->response_requested == event1.response_requested);
458 assert(result_event->is_notification == false);
459
460 event2.id = FWK_ID_EVENT(0x4, 7);
461 interrupt_get_current_return_val = true;
462 result = fwk_put_event(&event2);
463 assert(result == FWK_SUCCESS);
464 assert(fwk_list_is_empty(&ctx->free_event_queue));
465
466 /* Framework always queue light event by converting in a standard event */
467 result_event = FWK_LIST_GET(
468 fwk_list_pop_head(&ctx->isr_event_queue), struct fwk_event, slist_node);
469 assert(fwk_id_is_equal(result_event->source_id, event2.source_id));
470 assert(fwk_id_is_equal(result_event->target_id, event2.target_id));
471 assert(result_event->is_response == false);
472 assert(result_event->response_requested == event2.response_requested);
473 assert(result_event->is_notification == false);
474 }
475
test___fwk_put_notification(void)476 static void test___fwk_put_notification(void)
477 {
478 int result;
479 struct fwk_event *result_event;
480
481 struct fwk_event event1 = {
482 .source_id = FWK_ID_MODULE(0x1),
483 .target_id = FWK_ID_MODULE(0x2),
484 .is_response = false,
485 .response_requested = true,
486 .id = FWK_ID_EVENT(0x2, 7),
487 };
488
489 struct fwk_event event2 = {
490 .source_id = FWK_ID_MODULE(0x3),
491 .target_id = FWK_ID_MODULE(0x4),
492 .is_response = true,
493 .response_requested = false,
494 };
495
496 result = __fwk_init(2);
497 assert(result == FWK_SUCCESS);
498
499 result = __fwk_put_notification(&event1);
500 assert(result == FWK_SUCCESS);
501 result_event = FWK_LIST_GET(
502 fwk_list_pop_head(&ctx->event_queue), struct fwk_event, slist_node);
503 assert(fwk_id_is_equal(result_event->source_id, event1.source_id));
504 assert(fwk_id_is_equal(result_event->target_id, event1.target_id));
505 assert(result_event->is_response == false);
506 assert(result_event->response_requested == event1.response_requested);
507 assert(result_event->is_notification == true);
508
509 event2.id = FWK_ID_EVENT(0x4, 7);
510 interrupt_get_current_return_val = true;
511 result = __fwk_put_notification(&event2);
512 assert(result == FWK_SUCCESS);
513 assert(fwk_list_is_empty(&ctx->free_event_queue));
514 result_event = FWK_LIST_GET(
515 fwk_list_pop_head(&ctx->isr_event_queue), struct fwk_event, slist_node);
516 assert(fwk_id_is_equal(result_event->source_id, event2.source_id));
517 assert(fwk_id_is_equal(result_event->target_id, event2.target_id));
518 assert(result_event->is_response == false);
519 assert(result_event->response_requested == event2.response_requested);
520 assert(result_event->is_notification == true);
521 }
522
523 static const struct fwk_test_case_desc test_case_table[] = {
524 FWK_TEST_CASE(test___fwk_init),
525 FWK_TEST_CASE(test___fwk_run_main_loop),
526 FWK_TEST_CASE(test_fwk_put_event),
527 FWK_TEST_CASE(test_fwk_put_event_light),
528 FWK_TEST_CASE(test___fwk_put_notification)
529 };
530
531 struct fwk_test_suite_desc test_suite = {
532 .name = "fwk_core",
533 .test_suite_setup = test_suite_setup,
534 .test_case_setup = test_case_setup,
535 .test_case_teardown = test_case_teardown,
536 .test_case_count = FWK_ARRAY_SIZE(test_case_table),
537 .test_case_table = test_case_table,
538 };
539