zephyr/include/zephyr/init.h

251 lines
7.9 KiB
C

/*
* 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_ */