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(¬ification_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 = ¤t_event;
281 result = fwk_notification_notify(¬ification_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(¬ification_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(¬ification_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(¬ification_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 = ¤t_event;
343 notification_event.id = FWK_ID_NOTIFICATION(0x2, 0x1);
344 is_valid_entity_id_return_val = false;
345 result = fwk_notification_notify(¬ification_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