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