1 /*
2 * Copyright (c) 2013-2014 Wind River Systems, Inc.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /**
8 * @file
9 * @brief Full C support initialization
10 *
11 *
12 * Initialization of full C support: zero the .bss, copy the .data if XIP,
13 * call z_cstart().
14 *
15 * Stack is available in this module, but not the global data/bss until their
16 * initialization is performed.
17 */
18
19 #include <zephyr/kernel.h>
20 #include <kernel_internal.h>
21 #include <zephyr/linker/linker-defs.h>
22 #include <zephyr/sys/barrier.h>
23 #include <zephyr/platform/hooks.h>
24 #include <zephyr/arch/cache.h>
25
26 #if defined(__GNUC__)
27 /*
28 * GCC can detect if memcpy is passed a NULL argument, however one of
29 * the cases of relocate_vector_table() it is valid to pass NULL, so we
30 * suppress the warning for this case. We need to do this before
31 * string.h is included to get the declaration of memcpy.
32 */
33 #pragma GCC diagnostic push
34 #pragma GCC diagnostic ignored "-Wnonnull"
35 #endif
36
37 #include <string.h>
38
39 #if defined(CONFIG_SW_VECTOR_RELAY) || defined(CONFIG_SW_VECTOR_RELAY_CLIENT)
40 Z_GENERIC_SECTION(.vt_pointer_section) __attribute__((used))
41 void *_vector_table_pointer;
42 #endif
43
44 #ifdef CONFIG_CPU_CORTEX_M_HAS_VTOR
45
46 #define VECTOR_ADDRESS ((uintptr_t)_vector_start)
47
48 /* In some Cortex-M3 implementations SCB_VTOR bit[29] is called the TBLBASE bit */
49 #ifdef SCB_VTOR_TBLBASE_Msk
50 #define VTOR_MASK (SCB_VTOR_TBLBASE_Msk | SCB_VTOR_TBLOFF_Msk)
51 #else
52 #define VTOR_MASK SCB_VTOR_TBLOFF_Msk
53 #endif
54
relocate_vector_table(void)55 static inline void relocate_vector_table(void)
56 {
57 SCB->VTOR = VECTOR_ADDRESS & VTOR_MASK;
58 barrier_dsync_fence_full();
59 barrier_isync_fence_full();
60 }
61
62 #else
63 #define VECTOR_ADDRESS 0
64
relocate_vector_table(void)65 void __weak relocate_vector_table(void)
66 {
67 #if defined(CONFIG_XIP) && (CONFIG_FLASH_BASE_ADDRESS != 0) || \
68 !defined(CONFIG_XIP) && (CONFIG_SRAM_BASE_ADDRESS != 0)
69 size_t vector_size = (size_t)_vector_end - (size_t)_vector_start;
70 (void)memcpy(VECTOR_ADDRESS, _vector_start, vector_size);
71 #elif defined(CONFIG_SW_VECTOR_RELAY) || defined(CONFIG_SW_VECTOR_RELAY_CLIENT)
72 _vector_table_pointer = _vector_start;
73 #endif
74 }
75
76 #if defined(__GNUC__)
77 #pragma GCC diagnostic pop
78 #endif
79
80 #endif /* CONFIG_CPU_CORTEX_M_HAS_VTOR */
81
82 #if defined(CONFIG_CPU_HAS_FPU)
z_arm_floating_point_init(void)83 static inline void z_arm_floating_point_init(void)
84 {
85 /*
86 * Upon reset, the Co-Processor Access Control Register is, normally,
87 * 0x00000000. However, it might be left un-cleared by firmware running
88 * before Zephyr boot.
89 */
90 SCB->CPACR &= (~(CPACR_CP10_Msk | CPACR_CP11_Msk));
91
92 #if defined(CONFIG_FPU)
93 /*
94 * Enable CP10 and CP11 Co-Processors to enable access to floating
95 * point registers.
96 */
97 #if defined(CONFIG_USERSPACE)
98 /* Full access */
99 SCB->CPACR |= CPACR_CP10_FULL_ACCESS | CPACR_CP11_FULL_ACCESS;
100 #else
101 /* Privileged access only */
102 SCB->CPACR |= CPACR_CP10_PRIV_ACCESS | CPACR_CP11_PRIV_ACCESS;
103 #endif /* CONFIG_USERSPACE */
104 /*
105 * Upon reset, the FPU Context Control Register is 0xC0000000
106 * (both Automatic and Lazy state preservation is enabled).
107 */
108 #if defined(CONFIG_MULTITHREADING) && !defined(CONFIG_FPU_SHARING)
109 /* Unshared FP registers (multithreading) mode. We disable the
110 * automatic stacking of FP registers (automatic setting of
111 * FPCA bit in the CONTROL register), upon exception entries,
112 * as the FP registers are to be used by a single context (and
113 * the use of FP registers in ISRs is not supported). This
114 * configuration improves interrupt latency and decreases the
115 * stack memory requirement for the (single) thread that makes
116 * use of the FP co-processor.
117 */
118 FPU->FPCCR &= (~(FPU_FPCCR_ASPEN_Msk | FPU_FPCCR_LSPEN_Msk));
119 #else
120 /*
121 * FP register sharing (multithreading) mode or single-threading mode.
122 *
123 * Enable both automatic and lazy state preservation of the FP context.
124 * The FPCA bit of the CONTROL register will be automatically set, if
125 * the thread uses the floating point registers. Because of lazy state
126 * preservation the volatile FP registers will not be stacked upon
127 * exception entry, however, the required area in the stack frame will
128 * be reserved for them. This configuration improves interrupt latency.
129 * The registers will eventually be stacked when the thread is swapped
130 * out during context-switch or if an ISR attempts to execute floating
131 * point instructions.
132 */
133 FPU->FPCCR = FPU_FPCCR_ASPEN_Msk | FPU_FPCCR_LSPEN_Msk;
134 #endif /* CONFIG_FPU_SHARING */
135
136 /* Make the side-effects of modifying the FPCCR be realized
137 * immediately.
138 */
139 barrier_dsync_fence_full();
140 barrier_isync_fence_full();
141
142 /* Initialize the Floating Point Status and Control Register. */
143 #if defined(CONFIG_ARMV8_1_M_MAINLINE)
144 /*
145 * For ARMv8.1-M with FPU, the FPSCR[18:16] LTPSIZE field must be set
146 * to 0b100 for "Tail predication not applied" as it's reset value
147 */
148 __set_FPSCR(4 << FPU_FPDSCR_LTPSIZE_Pos);
149 #else
150 __set_FPSCR(0);
151 #endif
152
153 /*
154 * Note:
155 * The use of the FP register bank is enabled, however the FP context
156 * will be activated (FPCA bit on the CONTROL register) in the presence
157 * of floating point instructions.
158 */
159
160 #endif /* CONFIG_FPU */
161
162 /*
163 * Upon reset, the CONTROL.FPCA bit is, normally, cleared. However,
164 * it might be left un-cleared by firmware running before Zephyr boot.
165 * We must clear this bit to prevent errors in exception unstacking.
166 *
167 * Note:
168 * In Sharing FP Registers mode CONTROL.FPCA is cleared before switching
169 * to main, so it may be skipped here (saving few boot cycles).
170 *
171 * If CONFIG_INIT_ARCH_HW_AT_BOOT is set, CONTROL is cleared at reset.
172 */
173 #if (!defined(CONFIG_FPU) || !defined(CONFIG_FPU_SHARING)) && \
174 (!defined(CONFIG_INIT_ARCH_HW_AT_BOOT))
175
176 __set_CONTROL(__get_CONTROL() & (~(CONTROL_FPCA_Msk)));
177 #endif
178 }
179
180 #endif /* CONFIG_CPU_HAS_FPU */
181
182 extern FUNC_NORETURN void z_cstart(void);
183
184 /**
185 *
186 * @brief Prepare to and run C code
187 *
188 * This routine prepares for the execution of and runs C code.
189 *
190 */
z_prep_c(void)191 void z_prep_c(void)
192 {
193 #if defined(CONFIG_SOC_PREP_HOOK)
194 soc_prep_hook();
195 #endif
196
197 relocate_vector_table();
198 #if defined(CONFIG_CPU_HAS_FPU)
199 z_arm_floating_point_init();
200 #endif
201 z_bss_zero();
202 z_data_copy();
203 #if defined(CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER)
204 /* Invoke SoC-specific interrupt controller initialization */
205 z_soc_irq_init();
206 #else
207 z_arm_interrupt_init();
208 #endif /* CONFIG_ARM_CUSTOM_INTERRUPT_CONTROLLER */
209 #if CONFIG_ARCH_CACHE
210 arch_cache_init();
211 #endif
212
213 #ifdef CONFIG_NULL_POINTER_EXCEPTION_DETECTION_DWT
214 z_arm_debug_enable_null_pointer_detection();
215 #endif
216 z_cstart();
217 CODE_UNREACHABLE;
218 }
219