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