1 /* 2 * Copyright (c) 2015 Intel Corporation. 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 7 #ifndef ZEPHYR_INCLUDE_INIT_H_ 8 #define ZEPHYR_INCLUDE_INIT_H_ 9 10 #include <stdint.h> 11 #include <stddef.h> 12 13 #include <zephyr/sys/util.h> 14 #include <zephyr/toolchain.h> 15 16 #ifdef __cplusplus 17 extern "C" { 18 #endif 19 20 /** 21 * @defgroup sys_init System Initialization 22 * @ingroup os_services 23 * 24 * Zephyr offers an infrastructure to call initialization code before `main`. 25 * Such initialization calls can be registered using SYS_INIT() or 26 * SYS_INIT_NAMED() macros. By using a combination of initialization levels and 27 * priorities init sequence can be adjusted as needed. The available 28 * initialization levels are described, in order, below: 29 * 30 * - `EARLY`: Used very early in the boot process, right after entering the C 31 * domain (``z_cstart()``). This can be used in architectures and SoCs that 32 * extend or implement architecture code and use drivers or system services 33 * that have to be initialized before the Kernel calls any architecture 34 * specific initialization code. 35 * - `PRE_KERNEL_1`: Executed in Kernel's initialization context, which uses 36 * the interrupt stack. At this point Kernel services are not yet available. 37 * - `PRE_KERNEL_2`: Same as `PRE_KERNEL_1`. 38 * - `POST_KERNEL`: Executed after Kernel is alive. From this point on, Kernel 39 * primitives can be used. 40 * - `APPLICATION`: Executed just before application code (`main`). 41 * - `SMP`: Only available if @kconfig{CONFIG_SMP} is enabled, specific for 42 * SMP. 43 * 44 * Initialization priority can take a value in the range of 0 to 99. 45 * 46 * @note The same infrastructure is used by devices. 47 * @{ 48 */ 49 50 struct device; 51 52 /** 53 * @brief Initialization function for init entries. 54 * 55 * Init entries support both the system initialization and the device 56 * APIs. Each API has its own init function signature; hence, we have a 57 * union to cover both. 58 */ 59 union init_function { 60 /** 61 * System initialization function. 62 * 63 * @retval 0 On success 64 * @retval -errno If init fails. 65 */ 66 int (*sys)(void); 67 /** 68 * Device initialization function. 69 * 70 * @param dev Device instance. 71 * 72 * @retval 0 On success 73 * @retval -errno If device initialization fails. 74 */ 75 int (*dev)(const struct device *dev); 76 #ifdef CONFIG_DEVICE_MUTABLE 77 /** 78 * Device initialization function (rw). 79 * 80 * @param dev Device instance. 81 * 82 * @retval 0 On success 83 * @retval -errno If device initialization fails. 84 */ 85 int (*dev_rw)(struct device *dev); 86 #endif 87 }; 88 89 /** 90 * @brief Structure to store initialization entry information. 91 * 92 * @internal 93 * Init entries need to be defined following these rules: 94 * 95 * - Their name must be set using Z_INIT_ENTRY_NAME(). 96 * - They must be placed in a special init section, given by 97 * Z_INIT_ENTRY_SECTION(). 98 * - They must be aligned, e.g. using Z_DECL_ALIGN(). 99 * 100 * See SYS_INIT_NAMED() for an example. 101 * @endinternal 102 */ 103 struct init_entry { 104 /** Initialization function. */ 105 union init_function init_fn; 106 /** 107 * If the init entry belongs to a device, this fields stores a 108 * reference to it, otherwise it is set to NULL. 109 */ 110 union { 111 const struct device *dev; 112 #ifdef CONFIG_DEVICE_MUTABLE 113 struct device *dev_rw; 114 #endif 115 }; 116 }; 117 118 /** @cond INTERNAL_HIDDEN */ 119 120 /* Helper definitions to evaluate level equality */ 121 #define Z_INIT_EARLY_EARLY 1 122 #define Z_INIT_PRE_KERNEL_1_PRE_KERNEL_1 1 123 #define Z_INIT_PRE_KERNEL_2_PRE_KERNEL_2 1 124 #define Z_INIT_POST_KERNEL_POST_KERNEL 1 125 #define Z_INIT_APPLICATION_APPLICATION 1 126 #define Z_INIT_SMP_SMP 1 127 128 /* Init level ordinals */ 129 #define Z_INIT_ORD_EARLY 0 130 #define Z_INIT_ORD_PRE_KERNEL_1 1 131 #define Z_INIT_ORD_PRE_KERNEL_2 2 132 #define Z_INIT_ORD_POST_KERNEL 3 133 #define Z_INIT_ORD_APPLICATION 4 134 #define Z_INIT_ORD_SMP 5 135 136 /** 137 * @brief Obtain init entry name. 138 * 139 * @param init_id Init entry unique identifier. 140 */ 141 #define Z_INIT_ENTRY_NAME(init_id) _CONCAT(__init_, init_id) 142 143 /** 144 * @brief Init entry section. 145 * 146 * Each init entry is placed in a section with a name crafted so that it allows 147 * linker scripts to sort them according to the specified 148 * level/priority/sub-priority. 149 */ 150 #define Z_INIT_ENTRY_SECTION(level, prio, sub_prio) \ 151 __attribute__((__section__( \ 152 ".z_init_" #level STRINGIFY(prio)"_" STRINGIFY(sub_prio)"_"))) 153 154 155 /* Designated initializers where added to C in C99. There were added to 156 * C++ 20 years later in a much more restricted form. C99 allows many 157 * variations: out of order, mix of designated and not, overlap, 158 * override,... but C++ allows none of these. See differences detailed 159 * in the P0329R0.pdf C++ proposal. 160 * Note __STDC_VERSION__ is undefined when compiling C++. 161 */ 162 #if defined(__STDC_VERSION__) && (__STDC_VERSION__) < 201100 163 164 /* Anonymous unions require C11. Some pre-C11 gcc versions have early 165 * support for anonymous unions but they require these braces when 166 * combined with C99 designated initializers, see longer discussion in 167 * #69411. 168 * These braces are compatible with any C version but not with C++20. 169 */ 170 # define Z_INIT_SYS_INIT_DEV_NULL { .dev = NULL } 171 172 #else 173 174 /* When using -std=c++20 or higher, g++ (v12.2.0) reject braces for 175 * initializing anonymous unions because it is technically a mix of 176 * designated and not designated initializers which is not allowed in 177 * C++. Interestingly, the _same_ g++ version does accept the braces above 178 * when using -std=c++17 or lower! 179 * The tests/lib/cpp/cxx/ added by commit 3d9c428d57bf invoke the C++ 180 * compiler with a range of different `-std=...` parameters without needing 181 * any manual configuration. 182 */ 183 # define Z_INIT_SYS_INIT_DEV_NULL .dev = NULL 184 185 #endif 186 187 /** @endcond */ 188 189 /** 190 * @brief Obtain the ordinal for an init level. 191 * 192 * @param level Init level (EARLY, PRE_KERNEL_1, PRE_KERNEL_2, POST_KERNEL, 193 * APPLICATION, SMP). 194 * 195 * @return Init level ordinal. 196 */ 197 #define INIT_LEVEL_ORD(level) \ 198 COND_CODE_1(Z_INIT_EARLY_##level, (Z_INIT_ORD_EARLY), \ 199 (COND_CODE_1(Z_INIT_PRE_KERNEL_1_##level, (Z_INIT_ORD_PRE_KERNEL_1), \ 200 (COND_CODE_1(Z_INIT_PRE_KERNEL_2_##level, (Z_INIT_ORD_PRE_KERNEL_2), \ 201 (COND_CODE_1(Z_INIT_POST_KERNEL_##level, (Z_INIT_ORD_POST_KERNEL), \ 202 (COND_CODE_1(Z_INIT_APPLICATION_##level, (Z_INIT_ORD_APPLICATION), \ 203 (COND_CODE_1(Z_INIT_SMP_##level, (Z_INIT_ORD_SMP), \ 204 (ZERO_OR_COMPILE_ERROR(0))))))))))))) 205 206 /** 207 * @brief Register an initialization function. 208 * 209 * The function will be called during system initialization according to the 210 * given level and priority. 211 * 212 * @param init_fn Initialization function. 213 * @param level Initialization level. Allowed tokens: `EARLY`, `PRE_KERNEL_1`, 214 * `PRE_KERNEL_2`, `POST_KERNEL`, `APPLICATION` and `SMP` if 215 * @kconfig{CONFIG_SMP} is enabled. 216 * @param prio Initialization priority within @p _level. Note that it must be a 217 * decimal integer literal without leading zeroes or sign (e.g. `32`), or an 218 * equivalent symbolic name (e.g. `#define MY_INIT_PRIO 32`); symbolic 219 * expressions are **not** permitted (e.g. 220 * `CONFIG_KERNEL_INIT_PRIORITY_DEFAULT + 5`). 221 */ 222 #define SYS_INIT(init_fn, level, prio) \ 223 SYS_INIT_NAMED(init_fn, init_fn, level, prio) 224 225 /** 226 * @brief Register an initialization function (named). 227 * 228 * @note This macro can be used for cases where the multiple init calls use the 229 * same init function. 230 * 231 * @param name Unique name for SYS_INIT entry. 232 * @param init_fn_ See SYS_INIT(). 233 * @param level See SYS_INIT(). 234 * @param prio See SYS_INIT(). 235 * 236 * @see SYS_INIT() 237 */ 238 #define SYS_INIT_NAMED(name, init_fn_, level, prio) \ 239 static const Z_DECL_ALIGN(struct init_entry) \ 240 Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ 241 Z_INIT_ENTRY_NAME(name) = {.init_fn = {.sys = (init_fn_)}, \ 242 Z_INIT_SYS_INIT_DEV_NULL} 243 244 /** @} */ 245 246 #ifdef __cplusplus 247 } 248 #endif 249 250 #endif /* ZEPHYR_INCLUDE_INIT_H_ */ 251