1 /*
2 * Copyright (c) 2020 Intel Corporation
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/irq_offload.h>
8 #include <zephyr/internal/syscall_handler.h>
9
10 #include <zephyr/ztest.h>
11 #include <zephyr/ztest_error_hook.h>
12
13 #define STACK_SIZE (1024 + CONFIG_TEST_EXTRA_STACK_SIZE)
14 #define THREAD_TEST_PRIORITY 5
15
16 static K_THREAD_STACK_DEFINE(tstack, STACK_SIZE);
17 static struct k_thread tdata;
18
19 static ZTEST_BMEM int case_type;
20
21 /* A semaphore using inside irq_offload */
22 extern struct k_sem offload_sem;
23
24 /* test case type */
25 enum {
26 ZTEST_CATCH_FATAL_ACCESS,
27 ZTEST_CATCH_FATAL_ILLEAGAL_INSTRUCTION,
28 ZTEST_CATCH_FATAL_DIVIDE_ZERO,
29 ZTEST_CATCH_FATAL_K_PANIC,
30 ZTEST_CATCH_FATAL_K_OOPS,
31 ZTEST_CATCH_FATAL_IN_ISR,
32 ZTEST_CATCH_ASSERT_FAIL,
33 ZTEST_CATCH_ASSERT_IN_ISR,
34 ZTEST_CATCH_USER_FATAL_K_OOPS,
35 ZTEST_ERROR_MAX
36 } error_case_type;
37
38
trigger_assert_fail(void * a)39 static void trigger_assert_fail(void *a)
40 {
41 /* trigger an assert fail condition */
42 __ASSERT(a != NULL, "parameter a should not be NULL!");
43 }
44
45 /*
46 * Do not optimize to prevent GCC from generating invalid
47 * opcode exception instruction instead of real instruction.
48 */
trigger_fault_illegal_instruction(void)49 __no_optimization static void trigger_fault_illegal_instruction(void)
50 {
51 void *a = NULL;
52
53 /* execute an illegal instruction */
54 ((void(*)(void))&a)();
55 #ifdef CONFIG_RX
56 /*
57 * Intentionally execute an illegal instruction by calling a NULL pointer.
58 * Optimization is disabled to avoid GCC internal error during DWARF frame generation.
59 * __builtin_unreachable() hints to the compiler that control flow never returns here,
60 * which prevents faulty CFA emission on RX targets.
61 */
62 __builtin_unreachable();
63 #endif
64 }
65
66 /*
67 * Do not optimize to prevent GCC from generating invalid
68 * opcode exception instruction instead of real instruction.
69 */
trigger_fault_access(void)70 __no_optimization static void trigger_fault_access(void)
71 {
72 #if defined(CONFIG_SOC_ARC_IOT) || defined(CONFIG_SOC_FAMILY_NSIM_ARC_CLASSIC) || \
73 defined(CONFIG_SOC_FAMILY_NSIM_ARC_V) || defined(CONFIG_SOC_EMSK)
74 /* For iotdk, em_starterkit and ARC/nSIM, nSIM simulates full address space of
75 * memory, iotdk has eflash at 0x0 address, em_starterkit has ICCM at 0x0 address,
76 * access to 0x0 address doesn't generate any exception. So we access to 0XFFFFFFFF
77 * address instead to trigger exception. See issue #31419.
78 */
79 void *a = (void *)0xFFFFFFFF;
80 #elif defined(CONFIG_CPU_CORTEX_M) || defined(CONFIG_CPU_AARCH32_CORTEX_R) || \
81 defined(CONFIG_CPU_AARCH64_CORTEX_R)
82 /* As this test case only runs when User Mode is enabled,
83 * accessing _current always triggers a memory access fault,
84 * and is guaranteed not to trigger SecureFault exceptions.
85 */
86 void *a = (void *)_current;
87 #else
88 /* For most arch which support userspace, dereferencing NULL
89 * pointer will be caught by exception.
90 *
91 * Note: this is not applicable for ARM Cortex-M:
92 * In Cortex-M, nPRIV read access to address 0x0 is generally allowed,
93 * provided that it is "mapped" e.g. when CONFIG_FLASH_BASE_ADDRESS is
94 * 0x0. So, de-referencing NULL pointer is not guaranteed to trigger an
95 * exception.
96 */
97 void *a = (void *)NULL;
98 #endif
99 /* access an illegal address */
100 volatile int b = *((int *)a);
101
102 printk("b is %d\n", b);
103 }
104
105
106 /*
107 * Do not optimize the divide instruction. GCC will generate invalid
108 * opcode exception instruction instead of real divide instruction.
109 */
trigger_fault_divide_zero(void)110 __no_optimization static void trigger_fault_divide_zero(void)
111 {
112 int a = 1;
113 int b = 0;
114
115 /* divide by zero */
116 a = a / b;
117 printk("a is %d\n", a);
118
119 /*
120 * While no optimization is enabled, some QEMU such as QEMU cortex a53
121 * series, QEMU mps2 and mps3 series and QEMU ARC series boards will not
122 * trigger an exception for divide zero. They might need to enable the divide
123 * zero exception. We only skip the QEMU board here, this means this
124 * test will still apply on the physical board.
125 * For the Cortex-M0, M0+, M23 (CONFIG_ARMV6_M_ARMV8_M_BASELINE)
126 * which does not include a divide instruction, the test is skipped,
127 * and there will be no hardware exception for that.
128 * For ARMv8-R, divide by zero trapping is not supported in hardware.
129 */
130 #if (defined(CONFIG_SOC_SERIES_MPS2) && defined(CONFIG_QEMU_TARGET)) || \
131 (defined(CONFIG_SOC_SERIES_MPS3) && defined(CONFIG_QEMU_TARGET)) || \
132 defined(CONFIG_BOARD_QEMU_CORTEX_A53) || defined(CONFIG_SOC_QEMU_ARC) || \
133 defined(CONFIG_SOC_CORTEX_R8_VIRTUAL) || \
134 defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE) || \
135 defined(CONFIG_BOARD_QEMU_CORTEX_R5) || \
136 defined(CONFIG_ARMV8_R) || defined(CONFIG_AARCH32_ARMV8_R) || \
137 defined(CONFIG_BOARD_FVP_BASE_REVC_2XAEM) || \
138 defined(CONFIG_SOC_NSIM_EM11D)
139 ztest_test_skip();
140 #endif
141 }
142
trigger_fault_oops(void)143 static void trigger_fault_oops(void)
144 {
145 k_oops();
146 }
147
trigger_fault_panic(void)148 static void trigger_fault_panic(void)
149 {
150 k_panic();
151 }
152
release_offload_sem(void)153 static void release_offload_sem(void)
154 {
155 /* Semaphore used inside irq_offload needs to be
156 * released after an assert or a fault has happened.
157 */
158 k_sem_give(&offload_sem);
159 }
160
161 /* This is the fatal error hook that allows you to do actions after
162 * the fatal error has occurred. This is optional; you can choose
163 * to define the hook yourself. If not, the program will use the
164 * default one.
165 */
ztest_post_fatal_error_hook(unsigned int reason,const struct arch_esf * pEsf)166 void ztest_post_fatal_error_hook(unsigned int reason,
167 const struct arch_esf *pEsf)
168 {
169 switch (case_type) {
170 case ZTEST_CATCH_FATAL_ACCESS:
171 case ZTEST_CATCH_FATAL_ILLEAGAL_INSTRUCTION:
172 case ZTEST_CATCH_FATAL_DIVIDE_ZERO:
173 case ZTEST_CATCH_FATAL_K_PANIC:
174 case ZTEST_CATCH_FATAL_K_OOPS:
175 case ZTEST_CATCH_USER_FATAL_K_OOPS:
176 zassert_true(true);
177 break;
178
179 /* Unfortunately, the case of trigger a fatal error
180 * inside ISR context still cannot be dealt with,
181 * So please don't use it this way.
182 */
183 case ZTEST_CATCH_FATAL_IN_ISR:
184 zassert_true(false);
185 break;
186 default:
187 zassert_true(false);
188 break;
189 }
190 }
191
192 /* This is the assert fail post hook that allows you to do actions after
193 * the assert fail happened. This is optional, you can choose to define
194 * the hook yourself. If not, the program will use the default one.
195 */
ztest_post_assert_fail_hook(void)196 void ztest_post_assert_fail_hook(void)
197 {
198 switch (case_type) {
199 case ZTEST_CATCH_ASSERT_FAIL:
200 ztest_test_pass();
201 break;
202 case ZTEST_CATCH_ASSERT_IN_ISR:
203 release_offload_sem();
204 ztest_test_pass();
205 break;
206
207 default:
208 ztest_test_fail();
209 break;
210 }
211 }
212
tThread_entry(void * p1,void * p2,void * p3)213 static void tThread_entry(void *p1, void *p2, void *p3)
214 {
215 ARG_UNUSED(p2);
216 ARG_UNUSED(p3);
217
218 int sub_type = *(int *)p1;
219
220 printk("case type is %d\n", case_type);
221
222 ztest_set_fault_valid(false);
223
224 switch (sub_type) {
225 case ZTEST_CATCH_FATAL_ACCESS:
226 ztest_set_fault_valid(true);
227 trigger_fault_access();
228 break;
229 case ZTEST_CATCH_FATAL_ILLEAGAL_INSTRUCTION:
230 ztest_set_fault_valid(true);
231 trigger_fault_illegal_instruction();
232 break;
233 case ZTEST_CATCH_FATAL_DIVIDE_ZERO:
234 ztest_set_fault_valid(true);
235 trigger_fault_divide_zero();
236 break;
237 case ZTEST_CATCH_FATAL_K_PANIC:
238 ztest_set_fault_valid(true);
239 trigger_fault_panic();
240 break;
241 case ZTEST_CATCH_FATAL_K_OOPS:
242 ztest_set_fault_valid(true);
243 trigger_fault_oops();
244 break;
245
246 default:
247 break;
248 }
249
250 /* should not reach here */
251 ztest_test_fail();
252 }
253
run_trigger_thread(int i)254 static int run_trigger_thread(int i)
255 {
256 int ret;
257 uint32_t perm = K_INHERIT_PERMS;
258
259 case_type = i;
260
261 if (k_is_user_context()) {
262 perm = perm | K_USER;
263 }
264
265 k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE,
266 tThread_entry,
267 (void *)&case_type, NULL, NULL,
268 K_PRIO_PREEMPT(THREAD_TEST_PRIORITY),
269 perm, K_NO_WAIT);
270
271 ret = k_thread_join(tid, K_FOREVER);
272
273 return ret;
274 }
275
276 /**
277 * @brief Test if a fatal error can be caught
278 *
279 * @details Valid a fatal error we triggered in thread context works.
280 * If the fatal error happened and the program enter assert_post_handler,
281 * that means fatal error triggered as expected.
282 */
ZTEST_USER(error_hook_tests,test_catch_fatal_error)283 ZTEST_USER(error_hook_tests, test_catch_fatal_error)
284 {
285 #if defined(CONFIG_USERSPACE)
286 run_trigger_thread(ZTEST_CATCH_FATAL_ACCESS);
287 run_trigger_thread(ZTEST_CATCH_FATAL_ILLEAGAL_INSTRUCTION);
288 #if !defined(CONFIG_RISCV)
289 /*
290 * Because RISC-V Arch doesn't trigger exception for division-by-zero,
291 * this test couldn't support RISC-V.
292 * (RISC-V ISA Manual v2.2, Ch6.2 Division Operation)
293 */
294 run_trigger_thread(ZTEST_CATCH_FATAL_DIVIDE_ZERO);
295 #endif
296 #endif
297 run_trigger_thread(ZTEST_CATCH_FATAL_K_PANIC);
298 run_trigger_thread(ZTEST_CATCH_FATAL_K_OOPS);
299 }
300
301 /**
302 * @brief Test if catching an assert works
303 *
304 * @details Valid the assert in thread context works or not. If the assert
305 * fail happened and the program enter assert_post_handler, that means
306 * assert works as expected.
307 */
ZTEST_USER(error_hook_tests,test_catch_assert_fail)308 ZTEST_USER(error_hook_tests, test_catch_assert_fail)
309 {
310 case_type = ZTEST_CATCH_ASSERT_FAIL;
311
312 printk("1\n");
313 ztest_set_assert_valid(false);
314
315 printk("2\n");
316 ztest_set_assert_valid(true);
317
318 printk("3\n");
319 trigger_assert_fail(NULL);
320
321 printk("4\n");
322 ztest_test_fail();
323 }
324
325 /* a handler using by irq_offload */
tIsr_assert(const void * p)326 static void tIsr_assert(const void *p)
327 {
328 ztest_set_assert_valid(true);
329 trigger_assert_fail(NULL);
330 }
331
332 /**
333 * @brief Test if an assert fail works in ISR context
334 *
335 * @details Valid the assert in ISR context works or not. If the assert
336 * fail happened and the program enter assert_post_handler, that means
337 * assert works as expected.
338 */
ZTEST(error_hook_tests,test_catch_assert_in_isr)339 ZTEST(error_hook_tests, test_catch_assert_in_isr)
340 {
341 case_type = ZTEST_CATCH_ASSERT_IN_ISR;
342 irq_offload(tIsr_assert, NULL);
343 }
344
345
346 #if defined(CONFIG_USERSPACE)
trigger_z_oops(void)347 static void trigger_z_oops(void)
348 {
349 /* Set up a dummy syscall frame, pointing to a valid area in memory. */
350 _current->syscall_frame = _image_ram_start;
351
352 K_OOPS(true);
353 }
354
355 /**
356 * @brief Test if a z_oops can be catched
357 *
358 * @details Valid a z_oops we triggered in thread context works.
359 * If the z_oops happened and the program enter our handler,
360 * that means z_oops triggered as expected. This test only for
361 * userspace.
362 */
ZTEST(error_hook_tests,test_catch_z_oops)363 ZTEST(error_hook_tests, test_catch_z_oops)
364 {
365 case_type = ZTEST_CATCH_USER_FATAL_K_OOPS;
366
367 ztest_set_fault_valid(true);
368 trigger_z_oops();
369 }
370 #endif
371
372
error_hook_tests_setup(void)373 static void *error_hook_tests_setup(void)
374 {
375 #if defined(CONFIG_USERSPACE)
376 k_thread_access_grant(k_current_get(), &tdata, &tstack);
377 #endif
378 return NULL;
379 }
380 ZTEST_SUITE(error_hook_tests, NULL, error_hook_tests_setup, NULL, NULL, NULL);
381
fail_assume_in_setup_setup(void)382 static void *fail_assume_in_setup_setup(void)
383 {
384 /* Fail the assume, will skip all the tests */
385 zassume_true(false);
386 return NULL;
387 }
388
389 ZTEST_SUITE(fail_assume_in_setup, NULL, fail_assume_in_setup_setup, NULL, NULL, NULL);
390
391 ZTEST_EXPECT_SKIP(fail_assume_in_setup, test_to_skip0);
ZTEST(fail_assume_in_setup,test_to_skip0)392 ZTEST(fail_assume_in_setup, test_to_skip0)
393 {
394 /* This test should never be run */
395 ztest_test_fail();
396 }
397
398 ZTEST_EXPECT_SKIP(fail_assume_in_setup, test_to_skip1);
ZTEST(fail_assume_in_setup,test_to_skip1)399 ZTEST(fail_assume_in_setup, test_to_skip1)
400 {
401 /* This test should never be run */
402 ztest_test_fail();
403 }
404
fail_assume_in_before_before(void * unused)405 static void fail_assume_in_before_before(void *unused)
406 {
407 ARG_UNUSED(unused);
408 zassume_true(false);
409 }
410
411 ZTEST_SUITE(fail_assume_in_before, NULL, NULL, fail_assume_in_before_before, NULL, NULL);
412
413 ZTEST_EXPECT_SKIP(fail_assume_in_before, test_to_skip0);
ZTEST(fail_assume_in_before,test_to_skip0)414 ZTEST(fail_assume_in_before, test_to_skip0)
415 {
416 /* This test should never be run */
417 ztest_test_fail();
418 }
419
420 ZTEST_EXPECT_SKIP(fail_assume_in_before, test_to_skip1);
ZTEST(fail_assume_in_before,test_to_skip1)421 ZTEST(fail_assume_in_before, test_to_skip1)
422 {
423 /* This test should never be run */
424 ztest_test_fail();
425 }
426
427 ZTEST_SUITE(fail_assume_in_test, NULL, NULL, NULL, NULL, NULL);
428
429 ZTEST_EXPECT_SKIP(fail_assume_in_test, test_to_skip);
ZTEST(fail_assume_in_test,test_to_skip)430 ZTEST(fail_assume_in_test, test_to_skip)
431 {
432 zassume_true(false);
433 ztest_test_fail();
434 }
435
test_main(void)436 void test_main(void)
437 {
438 ztest_run_test_suites(NULL, false, 1, 1);
439 /* Can't run ztest_verify_all_test_suites_ran() since some tests are
440 * skipped by design.
441 */
442 }
443