1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2018-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 /* Mock functions */
25 static void * fwk_mm_calloc_val;
26 static size_t fwk_mm_calloc_num;
27 static size_t fwk_mm_calloc_size;
28 static int fwk_mm_calloc_return_val;
__wrap_fwk_mm_calloc(size_t num,size_t size)29 void *__wrap_fwk_mm_calloc(size_t num, size_t size)
30 {
31     if (fwk_mm_calloc_return_val) {
32         fwk_mm_calloc_num = num;
33         fwk_mm_calloc_size = size;
34         fwk_mm_calloc_val = (void *)calloc(num, size);
35         return fwk_mm_calloc_val;
36     }
37 
38     fwk_mm_calloc_num = 0;
39     fwk_mm_calloc_size = 0;
40 
41     return NULL;
42 }
43 
44 static struct fwk_module_context fake_module_ctx;
45 static struct fwk_dlist fake_module_dlist_table[4];
__wrap_fwk_module_get_ctx(fwk_id_t id)46 struct fwk_module_context *__wrap_fwk_module_get_ctx(fwk_id_t id)
47 {
48     fake_module_ctx.subscription_dlist_table = fake_module_dlist_table;
49     return &fake_module_ctx;
50 }
51 
52 static struct fwk_element_ctx fake_element_ctx;
53 static struct fwk_dlist fake_element_dlist_table[4];
__wrap_fwk_module_get_element_ctx(fwk_id_t id)54 struct fwk_element_ctx *__wrap_fwk_module_get_element_ctx(fwk_id_t id)
55 {
56     fake_element_ctx.subscription_dlist_table = fake_element_dlist_table;
57     return &fake_element_ctx;
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_notification_id_return_val;
__wrap_fwk_module_is_valid_notification_id(fwk_id_t id)67 bool __wrap_fwk_module_is_valid_notification_id(fwk_id_t id)
68 {
69     return is_valid_notification_id_return_val;
70 }
71 
__wrap_fwk_interrupt_global_enable(void)72 int __wrap_fwk_interrupt_global_enable(void)
73 {
74     return FWK_SUCCESS;
75 }
76 
__wrap_fwk_interrupt_global_disable(void)77 int __wrap_fwk_interrupt_global_disable(void)
78 {
79     return FWK_SUCCESS;
80 }
81 
82 static bool interrupt_get_current_return_val;
__wrap_fwk_is_interrupt_context(void)83 bool __wrap_fwk_is_interrupt_context(void)
84 {
85     return interrupt_get_current_return_val;
86 }
87 
88 static struct fwk_event notification_event_table[4];
89 static unsigned int notification_event_count;
__wrap___fwk_put_notification(struct fwk_event * event)90 int __wrap___fwk_put_notification(struct fwk_event *event)
91 {
92     assert(notification_event_count < FWK_ARRAY_SIZE(notification_event_table));
93 
94     notification_event_table[notification_event_count++] = *event;
95 
96     return FWK_SUCCESS;
97 }
98 
99 static struct fwk_event *get_current_event_return_val;
__wrap___fwk_get_current_event(void)100 const struct fwk_event *__wrap___fwk_get_current_event(void)
101 {
102     return get_current_event_return_val;
103 }
104 
test_case_setup(void)105 static void test_case_setup(void)
106 {
107     unsigned int i;
108 
109     is_valid_entity_id_return_val = true;
110     is_valid_notification_id_return_val = true;
111     interrupt_get_current_return_val = false;
112     fwk_mm_calloc_return_val = true;
113     get_current_event_return_val = NULL;
114     notification_event_count = 0;
115 
116     for (i = 0; i < FWK_ARRAY_SIZE(fake_module_dlist_table); i++)
117         fwk_list_init(&fake_module_dlist_table[i]);
118 
119     for (i = 0; i < FWK_ARRAY_SIZE(fake_element_dlist_table); i++)
120         fwk_list_init(&fake_element_dlist_table[i]);
121 }
122 
test_case_teardown(void)123 static void test_case_teardown(void)
124 {
125     __fwk_notification_reset();
126 }
127 
test_fwk_notification_subscribe(void)128 static void test_fwk_notification_subscribe(void)
129 {
130     int result;
131 
132     /* Call from an ISR */
133     interrupt_get_current_return_val = true;
134     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x3),
135                                         FWK_ID_ELEMENT(0x2, 0x9),
136                                         FWK_ID_MODULE(0x4));
137     assert(result == FWK_E_HANDLER);
138     interrupt_get_current_return_val = false;
139 
140     /* Invalid entity ID */
141     is_valid_entity_id_return_val = false;
142     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x3),
143                                         FWK_ID_ELEMENT(0x2, 0x9),
144                                         FWK_ID_MODULE(0x4));
145     assert(result == FWK_E_PARAM);
146     is_valid_entity_id_return_val = true;
147 
148     /* Invalid notification ID */
149     is_valid_notification_id_return_val = false;
150     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x3),
151                                         FWK_ID_ELEMENT(0x2, 0x9),
152                                         FWK_ID_MODULE(0x4));
153     assert(result == FWK_E_PARAM);
154     is_valid_notification_id_return_val = true;
155 
156     /* Incompatible source and event identifier */
157     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x3, 0x3),
158                                         FWK_ID_ELEMENT(0x2, 0x9),
159                                         FWK_ID_MODULE(0x4));
160     assert(result == FWK_E_PARAM);
161 
162     /* Subscribe successfully to an element notification */
163     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x3),
164                                         FWK_ID_ELEMENT(0x2, 0x9),
165                                         FWK_ID_MODULE(0x4));
166     assert(result == FWK_SUCCESS);
167 
168     /* Try to subscribe to the same element notification */
169     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x3),
170                                         FWK_ID_ELEMENT(0x2, 0x9),
171                                         FWK_ID_MODULE(0x4));
172     assert(result == FWK_E_STATE);
173 
174     /* Subscribe successfully to a module notification */
175     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x1),
176                                         FWK_ID_MODULE(0x2),
177                                         FWK_ID_ELEMENT(0x4, 0x15));
178     assert(result == FWK_SUCCESS);
179 
180     /* Try to subscribe to the same module notification */
181     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x1),
182                                         FWK_ID_MODULE(0x2),
183                                         FWK_ID_ELEMENT(0x4, 0x15));
184     assert(result == FWK_E_STATE);
185 }
186 
test_fwk_notification_unsubscribe(void)187 static void test_fwk_notification_unsubscribe(void)
188 {
189     int result;
190 
191     /* Call from an ISR */
192     interrupt_get_current_return_val = true;
193     result = fwk_notification_unsubscribe(FWK_ID_NOTIFICATION(0x2, 0x3),
194                                           FWK_ID_ELEMENT(0x2, 0x9),
195                                           FWK_ID_MODULE(0x4));
196     assert(result == FWK_E_HANDLER);
197     interrupt_get_current_return_val = false;
198 
199     /* Invalid entity ID */
200     is_valid_entity_id_return_val = false;
201     result = fwk_notification_unsubscribe(FWK_ID_NOTIFICATION(0x2, 0x3),
202                                           FWK_ID_ELEMENT(0x2, 0x9),
203                                           FWK_ID_MODULE(0x4));
204     assert(result == FWK_E_PARAM);
205     is_valid_entity_id_return_val = true;
206 
207     /* Invalid notification ID */
208     is_valid_notification_id_return_val = false;
209     result = fwk_notification_unsubscribe(FWK_ID_NOTIFICATION(0x2, 0x3),
210                                           FWK_ID_ELEMENT(0x2, 0x9),
211                                           FWK_ID_MODULE(0x4));
212     assert(result == FWK_E_PARAM);
213     is_valid_notification_id_return_val = true;
214 
215     /* Incompatible source and event identifier */
216     result = fwk_notification_unsubscribe(FWK_ID_NOTIFICATION(0x3, 0x3),
217                                           FWK_ID_ELEMENT(0x2, 0x9),
218                                           FWK_ID_MODULE(0x4));
219     assert(result == FWK_E_PARAM);
220 
221     /* Subscribe to an element notification */
222     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x1),
223                                         FWK_ID_ELEMENT(0x2, 0x9),
224                                         FWK_ID_MODULE(0x4));
225     assert(result == FWK_SUCCESS);
226 
227     /* Subscribe to the same element notification for another target */
228     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x1),
229                                         FWK_ID_ELEMENT(0x2, 0x9),
230                                         FWK_ID_ELEMENT(0x6, 0x1));
231     assert(result == FWK_SUCCESS);
232 
233     /* Subscribe to a module notification */
234     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x1),
235                                         FWK_ID_MODULE(0x2),
236                                         FWK_ID_ELEMENT(0x4, 0x15));
237     assert(result == FWK_SUCCESS);
238 
239     /* Unsubscribe to a notification that has not been subscribed to */
240     result = fwk_notification_unsubscribe(FWK_ID_NOTIFICATION(0x2, 0x1),
241                                           FWK_ID_ELEMENT(0x2, 0x9),
242                                           FWK_ID_MODULE(0x6));
243     assert(result == FWK_E_STATE);
244 
245     /*
246      * Unsubscribe to the element notification that has been subscribed to
247      * first
248      */
249     result = fwk_notification_unsubscribe(FWK_ID_NOTIFICATION(0x2, 0x1),
250                                           FWK_ID_ELEMENT(0x2, 0x9),
251                                           FWK_ID_MODULE(0x4));
252     assert(result == FWK_SUCCESS);
253 
254     /* Subscribe to another element notification, the subscription freed in the
255        previous step is re-used */
256     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x3),
257                                         FWK_ID_MODULE(0x2),
258                                         FWK_ID_ELEMENT(0xC, 0xC));
259     assert(result == FWK_SUCCESS);
260 }
261 
test_fwk_notification_notify(void)262 static void test_fwk_notification_notify(void)
263 {
264     int result;
265     struct fwk_event notification_event, current_event;
266     unsigned int count;
267 
268     /* Call from an ISR, invalid source identifier */
269     interrupt_get_current_return_val = true;
270     is_valid_entity_id_return_val = false;
271     result = fwk_notification_notify(&notification_event, &count);
272     assert(result == FWK_E_PARAM);
273     interrupt_get_current_return_val = false;
274     is_valid_entity_id_return_val = true;
275 
276     /* Current event, incompatible notification and source identifier. */
277     current_event.target_id = FWK_ID_ELEMENT(0x2, 0x9);
278     notification_event.source_id = FWK_ID_ELEMENT(0x3, 0x9);
279     notification_event.id = FWK_ID_NOTIFICATION(0x2, 0x1);
280     get_current_event_return_val = &current_event;
281     result = fwk_notification_notify(&notification_event, &count);
282     assert(result == FWK_E_PARAM);
283     get_current_event_return_val = NULL;
284 
285     /* No current event, invalid notification identifier. */
286     is_valid_notification_id_return_val = false;
287     result = fwk_notification_notify(&notification_event, &count);
288     assert(result == FWK_E_PARAM);
289     is_valid_notification_id_return_val = true;
290 
291     /* No current event, incompatible notification and
292        source identifier. */
293     notification_event.source_id = FWK_ID_ELEMENT(0x2, 0x9);
294     notification_event.id = FWK_ID_NOTIFICATION(0x1, 0x1);
295     result = fwk_notification_notify(&notification_event, &count);
296     assert(result == FWK_E_PARAM);
297 
298     /* Subscribe to an element notification */
299     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x1),
300                                         FWK_ID_ELEMENT(0x2, 0x9),
301                                         FWK_ID_MODULE(0x4));
302     assert(result == FWK_SUCCESS);
303 
304     /* Subscribe to the same element notification for another target */
305     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x1),
306                                         FWK_ID_ELEMENT(0x2, 0x9),
307                                         FWK_ID_ELEMENT(0x6, 0x1));
308     assert(result == FWK_SUCCESS);
309 
310     /* Subscribe to a module notification */
311     result = fwk_notification_subscribe(FWK_ID_NOTIFICATION(0x2, 0x1),
312                                         FWK_ID_MODULE(0x2),
313                                         FWK_ID_ELEMENT(0x4, 0x15));
314     assert(result == FWK_SUCCESS);
315 
316     /* Send the notifications FWK_ID_NOTIFICATION(0x2, 0x1) from
317        FWK_ID_ELEMENT(0x2, 0x9) */
318     notification_event.source_id = FWK_ID_ELEMENT(0x2, 0x9);
319     notification_event.id = FWK_ID_NOTIFICATION(0x2, 0x1);
320     result = fwk_notification_notify(&notification_event, &count);
321     assert(result == FWK_SUCCESS);
322     assert(count == 2);
323     assert(notification_event_count == 2);
324     assert(fwk_id_is_equal(notification_event_table[0].source_id,
325                            FWK_ID_ELEMENT(0x2, 0x9)));
326     assert(fwk_id_is_equal(notification_event_table[0].target_id,
327                            FWK_ID_MODULE(0x4)));
328     assert(fwk_id_is_equal(notification_event_table[0].id,
329                            FWK_ID_NOTIFICATION(0x2, 0x1)));
330     assert(fwk_id_is_equal(notification_event_table[1].source_id,
331                            FWK_ID_ELEMENT(0x2, 0x9)));
332     assert(fwk_id_is_equal(notification_event_table[1].target_id,
333                            FWK_ID_ELEMENT(0x6, 0x1)));
334     assert(fwk_id_is_equal(notification_event_table[1].id,
335                            FWK_ID_NOTIFICATION(0x2, 0x1)));
336     notification_event_count = 0;
337 
338     /* Send the notification FWK_ID_NOTIFICATION(0x2, 0x1) from
339        FWK_ID_MODULE(0x2) */
340 
341     current_event.target_id = FWK_ID_MODULE(0x2);
342     get_current_event_return_val = &current_event;
343     notification_event.id = FWK_ID_NOTIFICATION(0x2, 0x1);
344     is_valid_entity_id_return_val = false;
345     result = fwk_notification_notify(&notification_event, &count);
346     assert(result == FWK_SUCCESS);
347     assert(count == 1);
348     assert(notification_event_count == 1);
349     assert(fwk_id_is_equal(notification_event_table[0].source_id,
350                            FWK_ID_MODULE(0x2)));
351     assert(fwk_id_is_equal(notification_event_table[0].target_id,
352                            FWK_ID_ELEMENT(0x4, 0x15)));
353     assert(fwk_id_is_equal(notification_event_table[0].id,
354                            FWK_ID_NOTIFICATION(0x2, 0x1)));
355     get_current_event_return_val = NULL;
356     notification_event_count = 0;
357 }
358 
359 static const struct fwk_test_case_desc test_case_table[] = {
360     FWK_TEST_CASE(test_fwk_notification_subscribe),
361     FWK_TEST_CASE(test_fwk_notification_unsubscribe),
362     FWK_TEST_CASE(test_fwk_notification_notify)
363 };
364 
365 struct fwk_test_suite_desc test_suite = {
366     .name = "fwk_core",
367     .test_case_setup = test_case_setup,
368     .test_case_teardown = test_case_teardown,
369     .test_case_count = FWK_ARRAY_SIZE(test_case_table),
370     .test_case_table = test_case_table,
371 };
372