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