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 #include <internal/fwk_interrupt.h>
8
9 #include <fwk_arch.h>
10 #include <fwk_assert.h>
11 #include <fwk_interrupt.h>
12 #include <fwk_macros.h>
13 #include <fwk_status.h>
14 #include <fwk_test.h>
15
16 #include <stdbool.h>
17 #include <stdint.h>
18
19 #define INTERRUPT_ID 42
20
21 /*
22 * Variables for the mock functions
23 */
24 static int is_enabled_return_val;
25 static int enable_return_val;
26 static int disable_return_val;
27 static int is_pending_return_val;
28 static int set_pending_return_val;
29 static int clear_pending_return_val;
30 static int set_isr_return_val;
31 static int set_isr_param_return_val;
32 static int set_isr_nmi_return_val;
33 static int set_isr_nmi_param_return_val;
34 static int set_isr_fault_return_val;
35 static int get_current_return_val;
36
fake_isr(void)37 static void fake_isr(void)
38 {
39 return;
40 }
41
fake_isr_param(uintptr_t param)42 static void fake_isr_param(uintptr_t param)
43 {
44 return;
45 }
46
global_enable(void)47 static int global_enable(void)
48 {
49 return FWK_SUCCESS;
50 }
51
global_disable(void)52 static int global_disable(void)
53 {
54 return FWK_SUCCESS;
55 }
56
is_enabled(unsigned int interrupt,bool * state)57 static int is_enabled(unsigned int interrupt, bool *state)
58 {
59 return is_enabled_return_val;
60 }
61
enable(unsigned int interrupt)62 static int enable(unsigned int interrupt)
63 {
64 return enable_return_val;
65 }
66
disable(unsigned int interrupt)67 static int disable(unsigned int interrupt)
68 {
69 return disable_return_val;
70 }
71
is_pending(unsigned int interrupt,bool * state)72 static int is_pending(unsigned int interrupt, bool *state)
73 {
74 return is_pending_return_val;
75 }
76
set_pending(unsigned int interrupt)77 static int set_pending(unsigned int interrupt)
78 {
79 return set_pending_return_val;
80 }
81
clear_pending(unsigned int interrupt)82 static int clear_pending(unsigned int interrupt)
83 {
84 return clear_pending_return_val;
85 }
86
set_isr(unsigned int interrupt,void (* isr)(void))87 static int set_isr(unsigned int interrupt, void (*isr)(void))
88 {
89 return set_isr_return_val;
90 }
91
set_isr_param(unsigned int interrupt,void (* isr)(uintptr_t p),uintptr_t p)92 static int set_isr_param(unsigned int interrupt,
93 void (*isr)(uintptr_t p),
94 uintptr_t p)
95 {
96 return set_isr_param_return_val;
97 }
98
set_isr_nmi(void (* isr)(void))99 static int set_isr_nmi(void (*isr)(void))
100 {
101 return set_isr_nmi_return_val;
102 }
103
set_isr_nmi_param(void (* isr)(uintptr_t p),uintptr_t p)104 static int set_isr_nmi_param(void (*isr)(uintptr_t p), uintptr_t p)
105 {
106 return set_isr_nmi_param_return_val;
107 }
108
set_isr_fault(void (* isr)(void))109 static int set_isr_fault(void (*isr)(void))
110 {
111 return set_isr_fault_return_val;
112 }
113
get_current(unsigned int * interrupt)114 static int get_current(unsigned int *interrupt)
115 {
116 return get_current_return_val;
117 }
118
is_interrupt_context(void)119 static bool is_interrupt_context(void)
120 {
121 return (get_current_return_val == FWK_SUCCESS);
122 }
123
124 static const struct fwk_arch_interrupt_driver driver = {
125 .global_enable = global_enable,
126 .global_disable = global_disable,
127 .is_enabled = is_enabled,
128 .enable = enable,
129 .disable = disable,
130 .is_pending = is_pending,
131 .set_pending = set_pending,
132 .clear_pending = clear_pending,
133 .set_isr_irq = set_isr,
134 .set_isr_irq_param = set_isr_param,
135 .set_isr_nmi = set_isr_nmi,
136 .set_isr_nmi_param = set_isr_nmi_param,
137 .set_isr_fault = set_isr_fault,
138 .get_current = get_current,
139 .is_interrupt_context = is_interrupt_context,
140 };
141
142 static const struct fwk_arch_interrupt_driver driver_invalid = {};
143
test_case_setup(void)144 static void test_case_setup(void)
145 {
146 is_enabled_return_val = FWK_E_HANDLER;
147 enable_return_val = FWK_E_HANDLER;
148 disable_return_val = FWK_E_HANDLER;
149 is_pending_return_val = FWK_E_HANDLER;
150 set_pending_return_val = FWK_E_HANDLER;
151 clear_pending_return_val = FWK_E_HANDLER;
152 set_isr_return_val = FWK_E_HANDLER;
153 set_isr_param_return_val = FWK_E_HANDLER;
154 set_isr_nmi_return_val = FWK_E_HANDLER;
155 set_isr_nmi_param_return_val = FWK_E_HANDLER;
156 set_isr_fault_return_val = FWK_E_HANDLER;
157 get_current_return_val = FWK_E_HANDLER;
158 }
159
test_fwk_interrupt_before_init(void)160 static void test_fwk_interrupt_before_init(void)
161 {
162 int result;
163 unsigned int interrupt = 1;
164 bool state;
165
166 result = fwk_interrupt_is_enabled(interrupt, &state);
167 assert(result == FWK_E_INIT);
168
169 result = fwk_interrupt_enable(interrupt);
170 assert(result == FWK_E_INIT);
171
172 result = fwk_interrupt_disable(interrupt);
173 assert(result == FWK_E_INIT);
174
175 result = fwk_interrupt_is_pending(interrupt, &state);
176 assert(result == FWK_E_INIT);
177
178 result = fwk_interrupt_set_pending(interrupt);
179 assert(result == FWK_E_INIT);
180
181 result = fwk_interrupt_clear_pending(interrupt);
182 assert(result == FWK_E_INIT);
183
184 result = fwk_interrupt_set_isr(interrupt, fake_isr);
185 assert(result == FWK_E_INIT);
186
187 result = fwk_interrupt_set_isr_param(interrupt, fake_isr_param, 0);
188 assert(result == FWK_E_INIT);
189
190 result = fwk_interrupt_set_isr_fault(fake_isr);
191 assert(result == FWK_E_INIT);
192
193 result = fwk_interrupt_get_current(&interrupt);
194 assert(result == FWK_E_INIT);
195
196 state = fwk_is_interrupt_context();
197 assert(state == false);
198 }
199
test_fwk_interrupt_init(void)200 static void test_fwk_interrupt_init(void)
201 {
202 int result;
203
204 result = fwk_interrupt_init(NULL);
205 assert(result == FWK_E_PARAM);
206
207 /* Driver has NULL value */
208 result = fwk_interrupt_init(&driver_invalid);
209 assert(result == FWK_E_PARAM);
210
211 result = fwk_interrupt_init(&driver);
212 assert(result == FWK_SUCCESS);
213 }
214
test_fwk_interrupt_critical_section(void)215 static void test_fwk_interrupt_critical_section(void)
216 {
217 unsigned int flags;
218
219 flags = fwk_interrupt_global_disable();
220 assert(critical_section_nest_level == 1);
221
222 fwk_interrupt_global_enable(flags);
223 assert(critical_section_nest_level == 0);
224 }
225
test_fwk_interrupt_is_enabled(void)226 static void test_fwk_interrupt_is_enabled(void)
227 {
228 bool state;
229 int result;
230
231 result = fwk_interrupt_is_enabled(INTERRUPT_ID, NULL);
232 assert(result == FWK_E_PARAM);
233
234 is_enabled_return_val = FWK_SUCCESS;
235 result = fwk_interrupt_is_enabled(INTERRUPT_ID, &state);
236 assert(result == FWK_SUCCESS);
237 }
238
test_fwk_interrupt_enable(void)239 static void test_fwk_interrupt_enable(void)
240 {
241 int result;
242
243 enable_return_val = FWK_SUCCESS;
244 result = fwk_interrupt_enable(INTERRUPT_ID);
245 assert(result == FWK_SUCCESS);
246 }
247
test_fwk_interrupt_disable(void)248 static void test_fwk_interrupt_disable(void)
249 {
250 int result;
251
252 disable_return_val = FWK_SUCCESS;
253 result = fwk_interrupt_disable(INTERRUPT_ID);
254 assert(result == FWK_SUCCESS);
255 }
256
test_fwk_interrupt_is_pending(void)257 static void test_fwk_interrupt_is_pending(void)
258 {
259 int result;
260 bool state;
261
262 result = fwk_interrupt_is_pending(INTERRUPT_ID, NULL);
263 assert(result == FWK_E_PARAM);
264
265 is_pending_return_val = FWK_SUCCESS;
266 result = fwk_interrupt_is_pending(INTERRUPT_ID, &state);
267 assert(result == FWK_SUCCESS);
268 }
269
test_fwk_interrupt_set_pending(void)270 static void test_fwk_interrupt_set_pending(void)
271 {
272 int result;
273
274 set_pending_return_val = FWK_SUCCESS;
275 result = fwk_interrupt_set_pending(INTERRUPT_ID);
276 assert(result == FWK_SUCCESS);
277 }
278
test_fwk_interrupt_clear_pending(void)279 static void test_fwk_interrupt_clear_pending(void)
280 {
281 int result;
282
283 clear_pending_return_val = FWK_SUCCESS;
284 result = fwk_interrupt_clear_pending(INTERRUPT_ID);
285 assert(result == FWK_SUCCESS);
286 }
287
test_fwk_interrupt_set_isr(void)288 static void test_fwk_interrupt_set_isr(void)
289 {
290 int result;
291
292 result = fwk_interrupt_set_isr(INTERRUPT_ID, NULL);
293 assert(result == FWK_E_PARAM);
294
295 set_isr_return_val = FWK_SUCCESS;
296 result = fwk_interrupt_set_isr(INTERRUPT_ID, fake_isr);
297 assert(result == FWK_SUCCESS);
298
299 set_isr_return_val = FWK_E_HANDLER;
300 set_isr_nmi_return_val = FWK_SUCCESS;
301 result = fwk_interrupt_set_isr(FWK_INTERRUPT_NMI, fake_isr);
302 assert(result == FWK_SUCCESS);
303 }
304
test_fwk_interrupt_set_isr_param(void)305 static void test_fwk_interrupt_set_isr_param(void)
306 {
307 int result;
308
309 result = fwk_interrupt_set_isr_param(INTERRUPT_ID, NULL, 0);
310 assert(result == FWK_E_PARAM);
311
312 set_isr_param_return_val = FWK_SUCCESS;
313 result = fwk_interrupt_set_isr_param(INTERRUPT_ID, fake_isr_param, 0);
314 assert(result == FWK_SUCCESS);
315
316 set_isr_param_return_val = FWK_E_HANDLER;
317 set_isr_nmi_param_return_val = FWK_SUCCESS;
318 result = fwk_interrupt_set_isr_param(FWK_INTERRUPT_NMI, fake_isr_param, 0);
319 assert(result == FWK_SUCCESS);
320 }
321
test_fwk_interrupt_set_isr_fault(void)322 static void test_fwk_interrupt_set_isr_fault(void)
323 {
324 int result;
325
326 result = fwk_interrupt_set_isr_fault(NULL);
327 assert(result == FWK_E_PARAM);
328
329 set_isr_fault_return_val = FWK_SUCCESS;
330 result = fwk_interrupt_set_isr_fault(fake_isr);
331 assert(result == FWK_SUCCESS);
332 }
333
test_fwk_interrupt_get_current(void)334 static void test_fwk_interrupt_get_current(void)
335 {
336 int result;
337 unsigned int interrupt;
338
339 result = fwk_interrupt_get_current(NULL);
340 assert(result == FWK_E_PARAM);
341
342 get_current_return_val = FWK_SUCCESS;
343 result = fwk_interrupt_get_current(&interrupt);
344 assert(result == FWK_SUCCESS);
345 }
346
test_fwk_interrupt_nested_critical_section(void)347 static void test_fwk_interrupt_nested_critical_section(void)
348 {
349 unsigned int flags1, flags2, flags3;
350 flags1 = fwk_interrupt_global_disable();
351 assert(critical_section_nest_level == 1);
352
353 flags2 = fwk_interrupt_global_disable();
354 assert(critical_section_nest_level == 2);
355
356 flags3 = fwk_interrupt_global_disable();
357 assert(critical_section_nest_level == 3);
358
359 fwk_interrupt_global_enable(flags3);
360 assert(critical_section_nest_level == 2);
361
362 fwk_interrupt_global_enable(flags2);
363 assert(critical_section_nest_level == 1);
364
365 fwk_interrupt_global_enable(flags1);
366 assert(critical_section_nest_level == 0);
367 }
368
369 static const struct fwk_test_case_desc test_case_table[] = {
370 FWK_TEST_CASE(test_fwk_interrupt_before_init),
371 FWK_TEST_CASE(test_fwk_interrupt_init),
372 FWK_TEST_CASE(test_fwk_interrupt_critical_section),
373 FWK_TEST_CASE(test_fwk_interrupt_is_enabled),
374 FWK_TEST_CASE(test_fwk_interrupt_enable),
375 FWK_TEST_CASE(test_fwk_interrupt_disable),
376 FWK_TEST_CASE(test_fwk_interrupt_is_pending),
377 FWK_TEST_CASE(test_fwk_interrupt_set_pending),
378 FWK_TEST_CASE(test_fwk_interrupt_clear_pending),
379 FWK_TEST_CASE(test_fwk_interrupt_set_isr),
380 FWK_TEST_CASE(test_fwk_interrupt_set_isr_param),
381 FWK_TEST_CASE(test_fwk_interrupt_set_isr_fault),
382 FWK_TEST_CASE(test_fwk_interrupt_get_current),
383 FWK_TEST_CASE(test_fwk_interrupt_nested_critical_section),
384 };
385
386 struct fwk_test_suite_desc test_suite = {
387 .name = "fwk_interrupt",
388 .test_case_setup = test_case_setup,
389 .test_case_count = FWK_ARRAY_SIZE(test_case_table),
390 .test_case_table = test_case_table,
391 };
392