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 == &notification1);
309     assert(processed_notification == &notification1);
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