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