1 /*
2  * Copyright (C) 2020, Intel Corporation
3  * Copyright (C) 2023, Nordic Semiconductor ASA
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef INCLUDE_ZEPHYR_SYS_ITERABLE_SECTIONS_H_
8 #define INCLUDE_ZEPHYR_SYS_ITERABLE_SECTIONS_H_
9 
10 #include <zephyr/sys/__assert.h>
11 #include <zephyr/toolchain.h>
12 
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16 
17 /**
18  * @brief Iterable Sections APIs
19  * @defgroup iterable_section_apis Iterable Sections APIs
20  * @ingroup os_services
21  * @{
22  */
23 
24 /**
25  * @brief Defines a new element for an iterable section for a generic type.
26  *
27  * @details
28  * Convenience helper combining __in_section() and Z_DECL_ALIGN().
29  * The section name will be '.[SECNAME].static.[SECTION_POSTFIX]'
30  *
31  * In the linker script, create output sections for these using
32  * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM().
33  *
34  * @note In order to store the element in ROM, a const specifier has to
35  * be added to the declaration: const TYPE_SECTION_ITERABLE(...);
36  *
37  * @param[in]  type data type of variable
38  * @param[in]  varname name of variable to place in section
39  * @param[in]  secname type name of iterable section.
40  * @param[in]  section_postfix postfix to use in section name
41  */
42 #define TYPE_SECTION_ITERABLE(type, varname, secname, section_postfix) \
43 	Z_DECL_ALIGN(type) varname \
44 	__in_section(_##secname, static, _CONCAT(section_postfix, _)) __used __noasan
45 
46 /**
47  * @brief iterable section start symbol for a generic type
48  *
49  * will return '_[OUT_TYPE]_list_start'.
50  *
51  * @param[in]  secname type name of iterable section.  For 'struct foobar' this
52  * would be TYPE_SECTION_START(foobar)
53  *
54  */
55 #define TYPE_SECTION_START(secname) _CONCAT(_##secname, _list_start)
56 
57 /**
58  * @brief iterable section end symbol for a generic type
59  *
60  * will return '_<SECNAME>_list_end'.
61  *
62  * @param[in]  secname type name of iterable section.  For 'struct foobar' this
63  * would be TYPE_SECTION_START(foobar)
64  */
65 #define TYPE_SECTION_END(secname) _CONCAT(_##secname, _list_end)
66 
67 /**
68  * @brief iterable section extern for start symbol for a generic type
69  *
70  * Helper macro to give extern for start of iterable section.  The macro
71  * typically will be called TYPE_SECTION_START_EXTERN(struct foobar, foobar).
72  * This allows the macro to hand different types as well as cases where the
73  * type and section name may differ.
74  *
75  * @param[in]  type data type of section
76  * @param[in]  secname name of output section
77  */
78 #define TYPE_SECTION_START_EXTERN(type, secname) \
79 	extern type TYPE_SECTION_START(secname)[]
80 
81 /**
82  * @brief iterable section extern for end symbol for a generic type
83  *
84  * Helper macro to give extern for end of iterable section.  The macro
85  * typically will be called TYPE_SECTION_END_EXTERN(struct foobar, foobar).
86  * This allows the macro to hand different types as well as cases where the
87  * type and section name may differ.
88  *
89  * @param[in]  type data type of section
90  * @param[in]  secname name of output section
91  */
92 #define TYPE_SECTION_END_EXTERN(type, secname) \
93 	extern type TYPE_SECTION_END(secname)[]
94 
95 /**
96  * @brief Iterate over a specified iterable section for a generic type
97  *
98  * @details
99  * Iterator for structure instances gathered by TYPE_SECTION_ITERABLE().
100  * The linker must provide a _<SECNAME>_list_start symbol and a
101  * _<SECNAME>_list_end symbol to mark the start and the end of the
102  * list of struct objects to iterate over. This is normally done using
103  * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script.
104  */
105 #define TYPE_SECTION_FOREACH(type, secname, iterator)		\
106 	TYPE_SECTION_START_EXTERN(type, secname);		\
107 	TYPE_SECTION_END_EXTERN(type, secname);		\
108 	for (type * iterator = TYPE_SECTION_START(secname); ({	\
109 		__ASSERT(iterator <= TYPE_SECTION_END(secname),\
110 			      "unexpected list end location");	\
111 		     iterator < TYPE_SECTION_END(secname);	\
112 	     });						\
113 	     iterator++)
114 
115 /**
116  * @brief Get element from section for a generic type.
117  *
118  * @note There is no protection against reading beyond the section.
119  *
120  * @param[in]  type type of element
121  * @param[in]  secname name of output section
122  * @param[in]  i Index.
123  * @param[out] dst Pointer to location where pointer to element is written.
124  */
125 #define TYPE_SECTION_GET(type, secname, i, dst) do { \
126 	TYPE_SECTION_START_EXTERN(type, secname); \
127 	*(dst) = &TYPE_SECTION_START(secname)[i]; \
128 } while (0)
129 
130 /**
131  * @brief Count elements in a section for a generic type.
132  *
133  * @param[in]  type type of element
134  * @param[in]  secname name of output section
135  * @param[out] dst Pointer to location where result is written.
136  */
137 #define TYPE_SECTION_COUNT(type, secname, dst) do { \
138 	TYPE_SECTION_START_EXTERN(type, secname); \
139 	TYPE_SECTION_END_EXTERN(type, secname); \
140 	*(dst) = ((uintptr_t)TYPE_SECTION_END(secname) - \
141 		  (uintptr_t)TYPE_SECTION_START(secname)) / sizeof(type); \
142 } while (0)
143 
144 /**
145  * @brief iterable section start symbol for a struct type
146  *
147  * @param[in]  struct_type data type of section
148  */
149 #define STRUCT_SECTION_START(struct_type) \
150 	TYPE_SECTION_START(struct_type)
151 
152 /**
153  * @brief iterable section extern for start symbol for a struct
154  *
155  * Helper macro to give extern for start of iterable section.
156  *
157  * @param[in]  struct_type data type of section
158  */
159 #define STRUCT_SECTION_START_EXTERN(struct_type) \
160 	TYPE_SECTION_START_EXTERN(struct struct_type, struct_type)
161 
162 /**
163  * @brief iterable section end symbol for a struct type
164  *
165  * @param[in]  struct_type data type of section
166  */
167 #define STRUCT_SECTION_END(struct_type) \
168 	TYPE_SECTION_END(struct_type)
169 
170 /**
171  * @brief iterable section extern for end symbol for a struct
172  *
173  * Helper macro to give extern for end of iterable section.
174  *
175  * @param[in]  struct_type data type of section
176  */
177 #define STRUCT_SECTION_END_EXTERN(struct_type) \
178 	TYPE_SECTION_END_EXTERN(struct struct_type, struct_type)
179 
180 /**
181  * @brief Defines a new element of alternate data type for an iterable section.
182  *
183  * @details
184  * Special variant of STRUCT_SECTION_ITERABLE(), for placing alternate
185  * data types within the iterable section of a specific data type. The
186  * data type sizes and semantics must be equivalent!
187  */
188 #define STRUCT_SECTION_ITERABLE_ALTERNATE(secname, struct_type, varname) \
189 	TYPE_SECTION_ITERABLE(struct struct_type, varname, secname, varname)
190 
191 /**
192  * @brief Defines an array of elements of alternate data type for an iterable
193  * section.
194  *
195  * @see STRUCT_SECTION_ITERABLE_ALTERNATE
196  */
197 #define STRUCT_SECTION_ITERABLE_ARRAY_ALTERNATE(secname, struct_type, varname, \
198 						size)                          \
199 	TYPE_SECTION_ITERABLE(struct struct_type, varname[size], secname,      \
200 			      varname)
201 
202 /**
203  * @brief Defines a new element for an iterable section.
204  *
205  * @details
206  * Convenience helper combining __in_section() and Z_DECL_ALIGN().
207  * The section name is the struct type prepended with an underscore.
208  * The subsection is "static" and the subsubsection is the variable name.
209  *
210  * In the linker script, create output sections for these using
211  * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM().
212  *
213  * @note In order to store the element in ROM, a const specifier has to
214  * be added to the declaration: const STRUCT_SECTION_ITERABLE(...);
215  */
216 #define STRUCT_SECTION_ITERABLE(struct_type, varname) \
217 	STRUCT_SECTION_ITERABLE_ALTERNATE(struct_type, struct_type, varname)
218 
219 /**
220  * @brief Defines an array of elements for an iterable section.
221  *
222  * @see STRUCT_SECTION_ITERABLE
223  */
224 #define STRUCT_SECTION_ITERABLE_ARRAY(struct_type, varname, size)              \
225 	STRUCT_SECTION_ITERABLE_ARRAY_ALTERNATE(struct_type, struct_type,      \
226 						varname, size)
227 
228 /**
229  * @brief Defines a new element for an iterable section with a custom name.
230  *
231  * The name can be used to customize how iterable section entries are sorted.
232  * @see STRUCT_SECTION_ITERABLE()
233  */
234 #define STRUCT_SECTION_ITERABLE_NAMED(struct_type, name, varname) \
235 	TYPE_SECTION_ITERABLE(struct struct_type, varname, struct_type, name)
236 
237 /**
238  * @brief Iterate over a specified iterable section (alternate).
239  *
240  * @details
241  * Iterator for structure instances gathered by STRUCT_SECTION_ITERABLE().
242  * The linker must provide a _<SECNAME>_list_start symbol and a
243  * _<SECNAME>_list_end symbol to mark the start and the end of the
244  * list of struct objects to iterate over. This is normally done using
245  * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script.
246  */
247 #define STRUCT_SECTION_FOREACH_ALTERNATE(secname, struct_type, iterator) \
248 	TYPE_SECTION_FOREACH(struct struct_type, secname, iterator)
249 
250 /**
251  * @brief Iterate over a specified iterable section.
252  *
253  * @details
254  * Iterator for structure instances gathered by STRUCT_SECTION_ITERABLE().
255  * The linker must provide a _<struct_type>_list_start symbol and a
256  * _<struct_type>_list_end symbol to mark the start and the end of the
257  * list of struct objects to iterate over. This is normally done using
258  * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script.
259  */
260 #define STRUCT_SECTION_FOREACH(struct_type, iterator) \
261 	STRUCT_SECTION_FOREACH_ALTERNATE(struct_type, struct_type, iterator)
262 
263 /**
264  * @brief Get element from section.
265  *
266  * @note There is no protection against reading beyond the section.
267  *
268  * @param[in]  struct_type Struct type.
269  * @param[in]  i Index.
270  * @param[out] dst Pointer to location where pointer to element is written.
271  */
272 #define STRUCT_SECTION_GET(struct_type, i, dst) \
273 	TYPE_SECTION_GET(struct struct_type, struct_type, i, dst)
274 
275 /**
276  * @brief Count elements in a section.
277  *
278  * @param[in]  struct_type Struct type
279  * @param[out] dst Pointer to location where result is written.
280  */
281 #define STRUCT_SECTION_COUNT(struct_type, dst) \
282 	TYPE_SECTION_COUNT(struct struct_type, struct_type, dst);
283 
284 /**
285  * @}
286  */ /* end of struct_section_apis */
287 
288 #ifdef __cplusplus
289 }
290 #endif
291 
292 #endif /* INCLUDE_ZEPHYR_SYS_ITERABLE_SECTIONS_H_ */
293