Line data Source code
1 0 : /*
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 1 : union init_function {
60 : /**
61 : * System initialization function.
62 : *
63 : * @retval 0 On success
64 : * @retval -errno If init fails.
65 : */
66 1 : 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 1 : 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 1 : struct init_entry {
104 : /** Initialization function. */
105 1 : 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 0 : const struct device *dev;
112 : #ifdef CONFIG_DEVICE_MUTABLE
113 : struct device *dev_rw;
114 : #endif
115 1 : };
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 1 : #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 1 : #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 1 : #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_ */
|