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