forked from nrfconnect/sdk-zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinit.h
250 lines (224 loc) · 7.88 KB
/
init.h
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
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/*
* 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_ */