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 Defines a new element for an iterable section with a custom name,
239  * placed in a custom section.
240  *
241  * The name can be used to customize how iterable section entries are sorted.
242  * @see STRUCT_SECTION_ITERABLE_NAMED()
243  */
244 #define STRUCT_SECTION_ITERABLE_NAMED_ALTERNATE(struct_type, secname, name, varname) \
245 	TYPE_SECTION_ITERABLE(struct struct_type, varname, secname, name)
246 
247 /**
248  * @brief Iterate over a specified iterable section (alternate).
249  *
250  * @details
251  * Iterator for structure instances gathered by STRUCT_SECTION_ITERABLE().
252  * The linker must provide a _<SECNAME>_list_start symbol and a
253  * _<SECNAME>_list_end symbol to mark the start and the end of the
254  * list of struct objects to iterate over. This is normally done using
255  * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script.
256  */
257 #define STRUCT_SECTION_FOREACH_ALTERNATE(secname, struct_type, iterator) \
258 	TYPE_SECTION_FOREACH(struct struct_type, secname, iterator)
259 
260 /**
261  * @brief Iterate over a specified iterable section.
262  *
263  * @details
264  * Iterator for structure instances gathered by STRUCT_SECTION_ITERABLE().
265  * The linker must provide a _<struct_type>_list_start symbol and a
266  * _<struct_type>_list_end symbol to mark the start and the end of the
267  * list of struct objects to iterate over. This is normally done using
268  * ITERABLE_SECTION_ROM() or ITERABLE_SECTION_RAM() in the linker script.
269  */
270 #define STRUCT_SECTION_FOREACH(struct_type, iterator) \
271 	STRUCT_SECTION_FOREACH_ALTERNATE(struct_type, struct_type, iterator)
272 
273 /**
274  * @brief Get element from section.
275  *
276  * @note There is no protection against reading beyond the section.
277  *
278  * @param[in]  struct_type Struct type.
279  * @param[in]  i Index.
280  * @param[out] dst Pointer to location where pointer to element is written.
281  */
282 #define STRUCT_SECTION_GET(struct_type, i, dst) \
283 	TYPE_SECTION_GET(struct struct_type, struct_type, i, dst)
284 
285 /**
286  * @brief Count elements in a section.
287  *
288  * @param[in]  struct_type Struct type
289  * @param[out] dst Pointer to location where result is written.
290  */
291 #define STRUCT_SECTION_COUNT(struct_type, dst) \
292 	TYPE_SECTION_COUNT(struct struct_type, struct_type, dst);
293 
294 /**
295  * @}
296  */ /* end of struct_section_apis */
297 
298 #ifdef __cplusplus
299 }
300 #endif
301 
302 #endif /* INCLUDE_ZEPHYR_SYS_ITERABLE_SECTIONS_H_ */
303