Loading...
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 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 | /* SPDX-License-Identifier: GPL-2.0+ */ /* * include/linker_lists.h * * Implementation of linker-generated arrays * * Copyright (C) 2012 Marek Vasut <marex@denx.de> */ #ifndef __LINKER_LISTS_H__ #define __LINKER_LISTS_H__ #include <linux/compiler.h> /* * There is no use in including this from ASM files. * So just don't define anything when included from ASM. */ #if !defined(__ASSEMBLY__) /** * llsym() - Access a linker-generated array entry * @_type: Data type of the entry * @_name: Name of the entry * @_list: name of the list. Should contain only characters allowed * in a C variable name! */ #define llsym(_type, _name, _list) \ ((_type *)&_u_boot_list_2_##_list##_2_##_name) /** * ll_entry_declare() - Declare linker-generated array entry * @_type: Data type of the entry * @_name: Name of the entry * @_list: name of the list. Should contain only characters allowed * in a C variable name! * * This macro declares a variable that is placed into a linker-generated * array. This is a basic building block for more advanced use of linker- * generated arrays. The user is expected to build their own macro wrapper * around this one. * * A variable declared using this macro must be compile-time initialized. * * Special precaution must be made when using this macro: * * 1) The _type must not contain the "static" keyword, otherwise the * entry is generated and can be iterated but is listed in the map * file and cannot be retrieved by name. * * 2) In case a section is declared that contains some array elements AND * a subsection of this section is declared and contains some elements, * it is imperative that the elements are of the same type. * * 3) In case an outer section is declared that contains some array elements * AND an inner subsection of this section is declared and contains some * elements, then when traversing the outer section, even the elements of * the inner sections are present in the array. * * Example: * * :: * * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub) = { * .x = 3, * .y = 4, * }; */ #define ll_entry_declare(_type, _name, _list) \ _type _u_boot_list_2_##_list##_2_##_name __aligned(4) \ __attribute__((unused)) \ __section("__u_boot_list_2_"#_list"_2_"#_name) /** * ll_entry_declare_list() - Declare a list of link-generated array entries * @_type: Data type of each entry * @_name: Name of the entry * @_list: name of the list. Should contain only characters allowed * in a C variable name! * * This is like ll_entry_declare() but creates multiple entries. It should * be assigned to an array. * * :: * * ll_entry_declare_list(struct my_sub_cmd, my_sub_cmd, cmd_sub) = { * { .x = 3, .y = 4 }, * { .x = 8, .y = 2 }, * { .x = 1, .y = 7 } * }; */ #define ll_entry_declare_list(_type, _name, _list) \ _type _u_boot_list_2_##_list##_2_##_name[] __aligned(4) \ __attribute__((unused)) \ __section("__u_boot_list_2_"#_list"_2_"#_name) /* * We need a 0-byte-size type for iterator symbols, and the compiler * does not allow defining objects of C type 'void'. Using an empty * struct is allowed by the compiler, but causes gcc versions 4.4 and * below to complain about aliasing. Therefore we use the next best * thing: zero-sized arrays, which are both 0-byte-size and exempt from * aliasing warnings. */ /** * ll_entry_start() - Point to first entry of linker-generated array * @_type: Data type of the entry * @_list: Name of the list in which this entry is placed * * This function returns ``(_type *)`` pointer to the very first entry of a * linker-generated array placed into subsection of __u_boot_list section * specified by _list argument. * * Since this macro defines an array start symbol, its leftmost index * must be 2 and its rightmost index must be 1. * * Example: * * :: * * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub); */ #define ll_entry_start(_type, _list) \ ({ \ static char start[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \ __attribute__((unused)) \ __section("__u_boot_list_2_"#_list"_1"); \ _type * tmp = (_type *)&start; \ asm("":"+r"(tmp)); \ tmp; \ }) /** * ll_entry_end() - Point after last entry of linker-generated array * @_type: Data type of the entry * @_list: Name of the list in which this entry is placed * (with underscores instead of dots) * * This function returns ``(_type *)`` pointer after the very last entry of * a linker-generated array placed into subsection of __u_boot_list * section specified by _list argument. * * Since this macro defines an array end symbol, its leftmost index * must be 2 and its rightmost index must be 3. * * The end symbol uses __aligned(1) to ensure it is placed immediately after * the last entry without any padding. This is critical for ll_entry_count() * to work correctly. * * If the end marker had a higher alignment (e.g., 4 or 32 bytes), the linker * might insert padding between the last entry and the end marker to satisfy * alignment requirements of the following section. This would cause pointer * subtraction (end - start) to produce incorrect results because the compiler * optimizes pointer division using magic-number multiplication, which only * works correctly when the byte span is an exact multiple of the struct size. * * With __aligned(1), the end marker is placed at exactly (start + n * sizeof) * where n is the number of entries, ensuring correct pointer arithmetic. * * Example: * * :: * * struct my_sub_cmd *msc = ll_entry_end(struct my_sub_cmd, cmd_sub); */ #define ll_entry_end(_type, _list) \ ({ \ static char end[0] __aligned(1) __attribute__((unused)) \ __section("__u_boot_list_2_"#_list"_3"); \ _type * tmp = (_type *)&end; \ asm("":"+r"(tmp)); \ tmp; \ }) /** * ll_entry_count() - Return the number of elements in linker-generated array * @_type: Data type of the entry * @_list: Name of the list of which the number of elements is computed * * This function returns the number of elements of a linker-generated array * placed into subsection of __u_boot_list section specified by _list * argument. The result is of an unsigned int type. * * Example: * * :: * * int i; * const unsigned int count = ll_entry_count(struct my_sub_cmd, cmd_sub); * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub); * for (i = 0; i < count; i++, msc++) * printf("Entry %i, x=%i y=%i\n", i, msc->x, msc->y); */ #define ll_entry_count(_type, _list) \ ({ \ _type *start = ll_entry_start(_type, _list); \ _type *end = ll_entry_end(_type, _list); \ unsigned int _ll_result = end - start; \ _ll_result; \ }) /** * Declares a symbol that points to the start/end of the list. * * @_sym: Arbitrary name for the symbol (to use later in the file) * @_type: Data type of the entry * @_list: Name of the list in which this entry is placed * * The name of the (new) symbol is arbitrary and can be anything that is not * already declared in the file where it appears. It is provided in _sym and * can then be used (later in the same file) within a data structure. * The _type and _list arguments must match those passed to ll_entry_start/end() * * Example: * * Here we want to record the start of each sub-command in a list. We have two * sub-commands, 'bob' and 'mary'. * * In bob.c:: * * ll_entry_declare(struct my_sub_cmd, bob_cmd, cmd_sub) = {...}; * * In mary.c:: * * ll_entry_declare(struct my_sub_cmd, mary_cmd, cmd_sub) = {...}; * * In a different file where we want a list the start of all sub-commands. * It is not possible to use ll_entry_start() in a data structure, due to its * use of code inside expressions - ({ ... }) - so this fails to compile: * * In sub_cmds.c:: * * struct cmd_sub *my_list[] = { * ll_entry_start(cmd_sub, bob), * ll_entry_start(cmd_sub, bob), * }; * * Instead, we can use:: * * ll_start_decl(bob, struct my_sub_cmd, cmd_sub); * ll_start_decl(mary, struct my_sub_cmd, cmd_sub); * * struct cmd_sub *my_list[] = { * bob, * mary, * }; * * So 'bob' is declared as symbol, a struct my_list * which points to the * start of the bob sub-commands. It is then used in my_list[] */ #define ll_start_decl(_sym, _type, _list) \ static _type _sym[0] __aligned(CONFIG_LINKER_LIST_ALIGN) \ __maybe_unused __section("__u_boot_list_2_" #_list "_1") /* * ll_end_decl uses __aligned(1) to avoid padding before the end marker. * See the comment for ll_entry_end() for a full explanation. */ #define ll_end_decl(_sym, _type, _list) \ static _type _sym[0] __aligned(1) \ __maybe_unused __section("__u_boot_list_2_" #_list "_3") /** * ll_entry_get() - Retrieve entry from linker-generated array by name * @_type: Data type of the entry * @_name: Name of the entry * @_list: Name of the list in which this entry is placed * * This function returns a pointer to a particular entry in linker-generated * array identified by the subsection of u_boot_list where the entry resides * and it's name. * * Example: * * :: * * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub) = { * .x = 3, * .y = 4, * }; * ... * struct my_sub_cmd *c = ll_entry_get(struct my_sub_cmd, my_sub_cmd, cmd_sub); */ #define ll_entry_get(_type, _name, _list) \ ({ \ extern _type _u_boot_list_2_##_list##_2_##_name \ __aligned(4); \ _type *_ll_result = \ &_u_boot_list_2_##_list##_2_##_name; \ _ll_result; \ }) /** * ll_entry_ref() - Get a reference to a linker-generated array entry * * Once an extern ll_entry_declare() has been used to declare the reference, * this macro allows the entry to be accessed. * * This is like ll_entry_get(), but without the extra code, so it is suitable * for putting into data structures. * * @_type: C type of the list entry, e.g. 'struct foo' * @_name: name of the entry * @_list: name of the list */ #define ll_entry_ref(_type, _name, _list) \ ((_type *)&_u_boot_list_2_##_list##_2_##_name) /** * ll_start() - Point to first entry of first linker-generated array * @_type: Data type of the entry * * This function returns ``(_type *)`` pointer to the very first entry of * the very first linker-generated array. * * Since this macro defines the start of the linker-generated arrays, * its leftmost index must be 1. * * Example: * * :: * * struct my_sub_cmd *msc = ll_start(struct my_sub_cmd); */ #define ll_start(_type) \ ({ \ static char start[0] __aligned(4) __attribute__((unused)) \ __section("__u_boot_list_1"); \ _type * tmp = (_type *)&start; \ asm("":"+r"(tmp)); \ tmp; \ }) /** * ll_end() - Point after last entry of last linker-generated array * @_type: Data type of the entry * * This function returns ``(_type *)`` pointer after the very last entry of * the very last linker-generated array. * * Since this macro defines the end of the linker-generated arrays, * its leftmost index must be 3. * * Example: * * :: * * struct my_sub_cmd *msc = ll_end(struct my_sub_cmd); */ #define ll_end(_type) \ ({ \ static char end[0] __aligned(4) __attribute__((unused)) \ __section("__u_boot_list_3"); \ _type * tmp = (_type *)&end; \ asm("":"+r"(tmp)); \ tmp; \ }) #endif /* __ASSEMBLY__ */ #endif /* __LINKER_LISTS_H__ */ |