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