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 <kernel.h>
20 #include <kernel_internal.h>
21 #include <linker/linker-defs.h>
22
23 #if defined(CONFIG_ARMV7_R)
24 #include <aarch32/cortex_a_r/stack.h>
25 #endif
26
27 #if defined(__GNUC__)
28 /*
29 * GCC can detect if memcpy is passed a NULL argument, however one of
30 * the cases of relocate_vector_table() it is valid to pass NULL, so we
31 * suppress the warning for this case. We need to do this before
32 * string.h is included to get the declaration of memcpy.
33 */
34 #pragma GCC diagnostic push
35 #pragma GCC diagnostic ignored "-Wnonnull"
36 #endif
37
38 #include <string.h>
39
40 #if defined(CONFIG_SW_VECTOR_RELAY) || defined(CONFIG_SW_VECTOR_RELAY_CLIENT)
41 Z_GENERIC_SECTION(.vt_pointer_section) __attribute__((used))
42 void *_vector_table_pointer;
43 #endif
44
45 #ifdef CONFIG_CPU_CORTEX_M_HAS_VTOR
46
47 #define VECTOR_ADDRESS ((uintptr_t)_vector_start)
48
relocate_vector_table(void)49 static inline void relocate_vector_table(void)
50 {
51 SCB->VTOR = VECTOR_ADDRESS & SCB_VTOR_TBLOFF_Msk;
52 __DSB();
53 __ISB();
54 }
55
56 #else
57
58 #define VECTOR_ADDRESS 0
59
relocate_vector_table(void)60 void __weak relocate_vector_table(void)
61 {
62 #if defined(CONFIG_XIP) && (CONFIG_FLASH_BASE_ADDRESS != 0) || \
63 !defined(CONFIG_XIP) && (CONFIG_SRAM_BASE_ADDRESS != 0)
64 size_t vector_size = (size_t)_vector_end - (size_t)_vector_start;
65 (void)memcpy(VECTOR_ADDRESS, _vector_start, vector_size);
66 #elif defined(CONFIG_SW_VECTOR_RELAY) || defined(CONFIG_SW_VECTOR_RELAY_CLIENT)
67 _vector_table_pointer = _vector_start;
68 #endif
69 }
70
71 #if defined(__GNUC__)
72 #pragma GCC diagnostic pop
73 #endif
74
75 #endif /* CONFIG_CPU_CORTEX_M_HAS_VTOR */
76
77 #if defined(CONFIG_CPU_HAS_FPU)
z_arm_floating_point_init(void)78 static inline void z_arm_floating_point_init(void)
79 {
80 /*
81 * Upon reset, the Co-Processor Access Control Register is, normally,
82 * 0x00000000. However, it might be left un-cleared by firmware running
83 * before Zephyr boot.
84 */
85 SCB->CPACR &= (~(CPACR_CP10_Msk | CPACR_CP11_Msk));
86
87 #if defined(CONFIG_FPU)
88 /*
89 * Enable CP10 and CP11 Co-Processors to enable access to floating
90 * point registers.
91 */
92 #if defined(CONFIG_USERSPACE)
93 /* Full access */
94 SCB->CPACR |= CPACR_CP10_FULL_ACCESS | CPACR_CP11_FULL_ACCESS;
95 #else
96 /* Privileged access only */
97 SCB->CPACR |= CPACR_CP10_PRIV_ACCESS | CPACR_CP11_PRIV_ACCESS;
98 #endif /* CONFIG_USERSPACE */
99 /*
100 * Upon reset, the FPU Context Control Register is 0xC0000000
101 * (both Automatic and Lazy state preservation is enabled).
102 */
103 #if defined(CONFIG_MULTITHREADING) && !defined(CONFIG_FPU_SHARING)
104 /* Unshared FP registers (multithreading) mode. We disable the
105 * automatic stacking of FP registers (automatic setting of
106 * FPCA bit in the CONTROL register), upon exception entries,
107 * as the FP registers are to be used by a single context (and
108 * the use of FP registers in ISRs is not supported). This
109 * configuration improves interrupt latency and decreases the
110 * stack memory requirement for the (single) thread that makes
111 * use of the FP co-processor.
112 */
113 FPU->FPCCR &= (~(FPU_FPCCR_ASPEN_Msk | FPU_FPCCR_LSPEN_Msk));
114 #else
115 /*
116 * FP register sharing (multithreading) mode or single-threading mode.
117 *
118 * Enable both automatic and lazy state preservation of the FP context.
119 * The FPCA bit of the CONTROL register will be automatically set, if
120 * the thread uses the floating point registers. Because of lazy state
121 * preservation the volatile FP registers will not be stacked upon
122 * exception entry, however, the required area in the stack frame will
123 * be reserved for them. This configuration improves interrupt latency.
124 * The registers will eventually be stacked when the thread is swapped
125 * out during context-switch or if an ISR attempts to execute floating
126 * point instructions.
127 */
128 FPU->FPCCR = FPU_FPCCR_ASPEN_Msk | FPU_FPCCR_LSPEN_Msk;
129 #endif /* CONFIG_FPU_SHARING */
130
131 /* Make the side-effects of modifying the FPCCR be realized
132 * immediately.
133 */
134 __DSB();
135 __ISB();
136
137 /* Initialize the Floating Point Status and Control Register. */
138 __set_FPSCR(0);
139
140 /*
141 * Note:
142 * The use of the FP register bank is enabled, however the FP context
143 * will be activated (FPCA bit on the CONTROL register) in the presence
144 * of floating point instructions.
145 */
146
147 #endif /* CONFIG_FPU */
148
149 /*
150 * Upon reset, the CONTROL.FPCA bit is, normally, cleared. However,
151 * it might be left un-cleared by firmware running before Zephyr boot.
152 * We must clear this bit to prevent errors in exception unstacking.
153 *
154 * Note:
155 * In Sharing FP Registers mode CONTROL.FPCA is cleared before switching
156 * to main, so it may be skipped here (saving few boot cycles).
157 *
158 * If CONFIG_INIT_ARCH_HW_AT_BOOT is set, CONTROL is cleared at reset.
159 */
160 #if (!defined(CONFIG_FPU) || !defined(CONFIG_FPU_SHARING)) && \
161 (!defined(CONFIG_INIT_ARCH_HW_AT_BOOT))
162
163 __set_CONTROL(__get_CONTROL() & (~(CONTROL_FPCA_Msk)));
164 #endif
165 }
166 #endif /* CONFIG_CPU_HAS_FPU */
167
168 extern FUNC_NORETURN void z_cstart(void);
169 /**
170 *
171 * @brief Prepare to and run C code
172 *
173 * This routine prepares for the execution of and runs C code.
174 *
175 * @return N/A
176 */
z_arm_prep_c(void)177 void z_arm_prep_c(void)
178 {
179 relocate_vector_table();
180 #if defined(CONFIG_CPU_HAS_FPU)
181 z_arm_floating_point_init();
182 #endif
183 z_bss_zero();
184 z_data_copy();
185 #if defined(CONFIG_ARMV7_R) && defined(CONFIG_INIT_STACKS)
186 z_arm_init_stacks();
187 #endif
188 z_arm_interrupt_init();
189 z_cstart();
190 CODE_UNREACHABLE;
191 }
192