| /* |
| * Copyright (c) 2015 Intel Corporation. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef ZEPHYR_INCLUDE_INIT_H_ |
| #define ZEPHYR_INCLUDE_INIT_H_ |
| |
| #include <stdint.h> |
| #include <stddef.h> |
| |
| #include <zephyr/sys/util.h> |
| #include <zephyr/toolchain.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * @defgroup sys_init System Initialization |
| * @ingroup os_services |
| * |
| * Zephyr offers an infrastructure to call initialization code before `main`. |
| * Such initialization calls can be registered using SYS_INIT() or |
| * SYS_INIT_NAMED() macros. By using a combination of initialization levels and |
| * priorities init sequence can be adjusted as needed. The available |
| * initialization levels are described, in order, below: |
| * |
| * - `EARLY`: Used very early in the boot process, right after entering the C |
| * domain (``z_cstart()``). This can be used in architectures and SoCs that |
| * extend or implement architecture code and use drivers or system services |
| * that have to be initialized before the Kernel calls any architecture |
| * specific initialization code. |
| * - `PRE_KERNEL_1`: Executed in Kernel's initialization context, which uses |
| * the interrupt stack. At this point Kernel services are not yet available. |
| * - `PRE_KERNEL_2`: Same as `PRE_KERNEL_1`. |
| * - `POST_KERNEL`: Executed after Kernel is alive. From this point on, Kernel |
| * primitives can be used. |
| * - `APPLICATION`: Executed just before application code (`main`). |
| * - `SMP`: Only available if @kconfig{CONFIG_SMP} is enabled, specific for |
| * SMP. |
| * |
| * Initialization priority can take a value in the range of 0 to 99. |
| * |
| * @note The same infrastructure is used by devices. |
| * @{ |
| */ |
| |
| struct device; |
| |
| /** |
| * @brief Initialization function for init entries. |
| * |
| * Init entries support both the system initialization and the device |
| * APIs. Each API has its own init function signature; hence, we have a |
| * union to cover both. |
| */ |
| union init_function { |
| /** |
| * System initialization function. |
| * |
| * @retval 0 On success |
| * @retval -errno If init fails. |
| */ |
| int (*sys)(void); |
| /** |
| * Device initialization function. |
| * |
| * @param dev Device instance. |
| * |
| * @retval 0 On success |
| * @retval -errno If device initialization fails. |
| */ |
| int (*dev)(const struct device *dev); |
| #ifdef CONFIG_DEVICE_MUTABLE |
| /** |
| * Device initialization function (rw). |
| * |
| * @param dev Device instance. |
| * |
| * @retval 0 On success |
| * @retval -errno If device initialization fails. |
| */ |
| int (*dev_rw)(struct device *dev); |
| #endif |
| }; |
| |
| /** |
| * @brief Structure to store initialization entry information. |
| * |
| * @internal |
| * Init entries need to be defined following these rules: |
| * |
| * - Their name must be set using Z_INIT_ENTRY_NAME(). |
| * - They must be placed in a special init section, given by |
| * Z_INIT_ENTRY_SECTION(). |
| * - They must be aligned, e.g. using Z_DECL_ALIGN(). |
| * |
| * See SYS_INIT_NAMED() for an example. |
| * @endinternal |
| */ |
| struct init_entry { |
| /** Initialization function. */ |
| union init_function init_fn; |
| /** |
| * If the init entry belongs to a device, this fields stores a |
| * reference to it, otherwise it is set to NULL. |
| */ |
| union { |
| const struct device *dev; |
| #ifdef CONFIG_DEVICE_MUTABLE |
| struct device *dev_rw; |
| #endif |
| }; |
| }; |
| |
| /** @cond INTERNAL_HIDDEN */ |
| |
| /* Helper definitions to evaluate level equality */ |
| #define Z_INIT_EARLY_EARLY 1 |
| #define Z_INIT_PRE_KERNEL_1_PRE_KERNEL_1 1 |
| #define Z_INIT_PRE_KERNEL_2_PRE_KERNEL_2 1 |
| #define Z_INIT_POST_KERNEL_POST_KERNEL 1 |
| #define Z_INIT_APPLICATION_APPLICATION 1 |
| #define Z_INIT_SMP_SMP 1 |
| |
| /* Init level ordinals */ |
| #define Z_INIT_ORD_EARLY 0 |
| #define Z_INIT_ORD_PRE_KERNEL_1 1 |
| #define Z_INIT_ORD_PRE_KERNEL_2 2 |
| #define Z_INIT_ORD_POST_KERNEL 3 |
| #define Z_INIT_ORD_APPLICATION 4 |
| #define Z_INIT_ORD_SMP 5 |
| |
| /** |
| * @brief Obtain init entry name. |
| * |
| * @param init_id Init entry unique identifier. |
| */ |
| #define Z_INIT_ENTRY_NAME(init_id) _CONCAT(__init_, init_id) |
| |
| /** |
| * @brief Init entry section. |
| * |
| * Each init entry is placed in a section with a name crafted so that it allows |
| * linker scripts to sort them according to the specified |
| * level/priority/sub-priority. |
| */ |
| #define Z_INIT_ENTRY_SECTION(level, prio, sub_prio) \ |
| __attribute__((__section__( \ |
| ".z_init_" #level STRINGIFY(prio)"_" STRINGIFY(sub_prio)"_"))) |
| |
| |
| /* Designated initializers where added to C in C99. There were added to |
| * C++ 20 years later in a much more restricted form. C99 allows many |
| * variations: out of order, mix of designated and not, overlap, |
| * override,... but C++ allows none of these. See differences detailed |
| * in the P0329R0.pdf C++ proposal. |
| * Note __STDC_VERSION__ is undefined when compiling C++. |
| */ |
| #if defined(__STDC_VERSION__) && (__STDC_VERSION__) < 201100 |
| |
| /* Anonymous unions require C11. Some pre-C11 gcc versions have early |
| * support for anonymous unions but they require these braces when |
| * combined with C99 designated initializers, see longer discussion in |
| * #69411. |
| * These braces are compatible with any C version but not with C++20. |
| */ |
| # define Z_INIT_SYS_INIT_DEV_NULL { .dev = NULL } |
| |
| #else |
| |
| /* When using -std=c++20 or higher, g++ (v12.2.0) reject braces for |
| * initializing anonymous unions because it is technically a mix of |
| * designated and not designated initializers which is not allowed in |
| * C++. Interestingly, the _same_ g++ version does accept the braces above |
| * when using -std=c++17 or lower! |
| * The tests/lib/cpp/cxx/ added by commit 3d9c428d57bf invoke the C++ |
| * compiler with a range of different `-std=...` parameters without needing |
| * any manual configuration. |
| */ |
| # define Z_INIT_SYS_INIT_DEV_NULL .dev = NULL |
| |
| #endif |
| |
| /** @endcond */ |
| |
| /** |
| * @brief Obtain the ordinal for an init level. |
| * |
| * @param level Init level (EARLY, PRE_KERNEL_1, PRE_KERNEL_2, POST_KERNEL, |
| * APPLICATION, SMP). |
| * |
| * @return Init level ordinal. |
| */ |
| #define INIT_LEVEL_ORD(level) \ |
| COND_CODE_1(Z_INIT_EARLY_##level, (Z_INIT_ORD_EARLY), \ |
| (COND_CODE_1(Z_INIT_PRE_KERNEL_1_##level, (Z_INIT_ORD_PRE_KERNEL_1), \ |
| (COND_CODE_1(Z_INIT_PRE_KERNEL_2_##level, (Z_INIT_ORD_PRE_KERNEL_2), \ |
| (COND_CODE_1(Z_INIT_POST_KERNEL_##level, (Z_INIT_ORD_POST_KERNEL), \ |
| (COND_CODE_1(Z_INIT_APPLICATION_##level, (Z_INIT_ORD_APPLICATION), \ |
| (COND_CODE_1(Z_INIT_SMP_##level, (Z_INIT_ORD_SMP), \ |
| (ZERO_OR_COMPILE_ERROR(0))))))))))))) |
| |
| /** |
| * @brief Register an initialization function. |
| * |
| * The function will be called during system initialization according to the |
| * given level and priority. |
| * |
| * @param init_fn Initialization function. |
| * @param level Initialization level. Allowed tokens: `EARLY`, `PRE_KERNEL_1`, |
| * `PRE_KERNEL_2`, `POST_KERNEL`, `APPLICATION` and `SMP` if |
| * @kconfig{CONFIG_SMP} is enabled. |
| * @param prio Initialization priority within @p _level. Note that it must be a |
| * decimal integer literal without leading zeroes or sign (e.g. `32`), or an |
| * equivalent symbolic name (e.g. `#define MY_INIT_PRIO 32`); symbolic |
| * expressions are **not** permitted (e.g. |
| * `CONFIG_KERNEL_INIT_PRIORITY_DEFAULT + 5`). |
| */ |
| #define SYS_INIT(init_fn, level, prio) \ |
| SYS_INIT_NAMED(init_fn, init_fn, level, prio) |
| |
| /** |
| * @brief Register an initialization function (named). |
| * |
| * @note This macro can be used for cases where the multiple init calls use the |
| * same init function. |
| * |
| * @param name Unique name for SYS_INIT entry. |
| * @param init_fn_ See SYS_INIT(). |
| * @param level See SYS_INIT(). |
| * @param prio See SYS_INIT(). |
| * |
| * @see SYS_INIT() |
| */ |
| #define SYS_INIT_NAMED(name, init_fn_, level, prio) \ |
| static const Z_DECL_ALIGN(struct init_entry) \ |
| Z_INIT_ENTRY_SECTION(level, prio, 0) __used __noasan \ |
| Z_INIT_ENTRY_NAME(name) = {.init_fn = {.sys = (init_fn_)}, \ |
| Z_INIT_SYS_INIT_DEV_NULL} |
| |
| /** @} */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* ZEPHYR_INCLUDE_INIT_H_ */ |