1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/printk.h>
9 #include <zephyr/sys/__assert.h>
10 #include <cmsis_core.h>
11 #include <zephyr/sys/barrier.h>
12
13 #if !defined(CONFIG_CPU_CORTEX_M)
14 #error test can only run on Cortex-M MCUs
15 #endif
16
17 #if defined(CONFIG_ARMV8_1_M_MAINLINE)
18 /*
19 * For ARMv8.1-M, the FPSCR[18:16] LTPSIZE field may always read 0b010 if MVE
20 * is not implemented, so mask it when validating the value of the FPSCR.
21 */
22 #define FPSCR_MASK (~FPU_FPDSCR_LTPSIZE_Msk)
23 #else
24 #define FPSCR_MASK (0xffffffffU)
25 #endif
26
27 K_THREAD_STACK_DECLARE(z_main_stack, CONFIG_MAIN_STACK_SIZE);
28
29 static volatile int test_flag;
30 static unsigned int expected_reason;
31
arm_isr_handler(const void * args)32 void arm_isr_handler(const void *args)
33 {
34 ARG_UNUSED(args);
35
36 test_flag++;
37 }
38
k_sys_fatal_error_handler(unsigned int reason,const struct arch_esf * pEsf)39 void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *pEsf)
40 {
41 printk("Caught system error -- reason %d\n", reason);
42
43 if (expected_reason == -1) {
44 printk("Was not expecting a crash\n");
45 k_fatal_halt(reason);
46 }
47
48 if (reason != expected_reason) {
49 printk("Wrong crash type got %d expected %d\n", reason, expected_reason);
50 k_fatal_halt(reason);
51 }
52
53 expected_reason = -1;
54 }
55
test_main(void)56 void test_main(void)
57 {
58 printk("ARM no-multithreading test\n");
59
60 uint32_t psp = (uint32_t)__get_PSP();
61 uint32_t main_stack_base = (uint32_t)K_THREAD_STACK_BUFFER(z_main_stack);
62 uint32_t main_stack_top = (uint32_t)(K_THREAD_STACK_BUFFER(z_main_stack) +
63 K_THREAD_STACK_SIZEOF(z_main_stack));
64
65 __ASSERT((psp >= main_stack_base) && (psp <= main_stack_top),
66 "PSP out of bounds: 0x%x (0x%x - 0x%x)", psp, main_stack_base, main_stack_top);
67
68 #if defined(CONFIG_FPU)
69 __ASSERT((__get_FPSCR() & FPSCR_MASK) == 0, "FPSCR not zero (0x%x)", __get_FPSCR());
70 #endif
71
72 #if defined(CONFIG_BUILTIN_STACK_GUARD)
73 uint32_t psplim = (uint32_t)__get_PSPLIM();
74 __ASSERT((psplim == main_stack_base), "PSPLIM not set to main stack base: (0x%x)", psplim);
75 #endif
76
77 int key = arch_irq_lock();
78 __ASSERT(arch_irq_unlocked(key), "IRQs locked in main()");
79
80 arch_irq_unlock(key);
81
82 /* Verify activating the PendSV IRQ triggers a K_ERR_SPURIOUS_IRQ */
83 expected_reason = K_ERR_CPU_EXCEPTION;
84 SCB->ICSR |= SCB_ICSR_PENDSVSET_Msk;
85 barrier_dsync_fence_full();
86 barrier_isync_fence_full();
87
88 /* Determine an NVIC IRQ line that is not currently in use. */
89 int i, flag = test_flag;
90
91 __ASSERT(flag == 0, "Test flag not initialized to 0\n");
92
93 for (i = CONFIG_NUM_IRQS - 1; i >= 0; i--) {
94 if (NVIC_GetEnableIRQ(i) == 0) {
95 /*
96 * Interrupts configured statically with IRQ_CONNECT(.)
97 * are automatically enabled. NVIC_GetEnableIRQ()
98 * returning false, here, implies that the IRQ line is
99 * either not implemented or it is not enabled, thus,
100 * currently not in use by Zephyr.
101 */
102
103 /* Set the NVIC line to pending. */
104 NVIC_SetPendingIRQ(i);
105
106 if (NVIC_GetPendingIRQ(i)) {
107 /* If the NVIC line is pending, it is
108 * guaranteed that it is implemented; clear the
109 * line.
110 */
111 NVIC_ClearPendingIRQ(i);
112
113 if (!NVIC_GetPendingIRQ(i)) {
114 /*
115 * If the NVIC line can be successfully
116 * un-pended, it is guaranteed that it
117 * can be used for software interrupt
118 * triggering. Trigger it.
119 */
120 NVIC_SetPendingIRQ(i);
121 break;
122 }
123 }
124 }
125 }
126
127 if (i >= 0) {
128
129 printk("Available IRQ line: %u\n", i);
130
131 arch_irq_connect_dynamic(i, 0 /* highest priority */, arm_isr_handler, NULL, 0);
132
133 NVIC_EnableIRQ(i);
134
135 barrier_dsync_fence_full();
136 barrier_isync_fence_full();
137
138 flag = test_flag;
139
140 __ASSERT(flag > 0, "Test flag not set by IRQ\n");
141
142 printk("ARM no multithreading test successful\n");
143 } else {
144 __ASSERT(0, "No available IRQ line to use in the test\n");
145 }
146 }
147