1 /* 2 * include/linker_lists.h 3 * 4 * Implementation of linker-generated arrays 5 * 6 * Copyright (C) 2012 Marek Vasut <marex@denx.de> 7 * 8 * See file CREDITS for list of people who contributed to this 9 * project. 10 * 11 * This program is free software; you can redistribute it and/or 12 * modify it under the terms of the GNU General Public License as 13 * published by the Free Software Foundation; either version 2 of 14 * the License, or (at your option) any later version. 15 */ 16 #ifndef __LINKER_LISTS_H__ 17 #define __LINKER_LISTS_H__ 18 19 /** 20 * ll_entry_declare() - Declare linker-generated array entry 21 * @_type: Data type of the entry 22 * @_name: Name of the entry 23 * @_section_u: Subsection of u_boot_list in which this entry is placed 24 * (with underscores instead of dots, for name concatenation) 25 * @_section_d: Subsection of u_boot_list in which this entry is placed 26 * (with dots, for section concatenation) 27 * 28 * This macro declares a variable that is placed into a linker-generated 29 * array. This is a basic building block for more advanced use of linker- 30 * generated arrays. The user is expected to build their own macro wrapper 31 * around this one. 32 * 33 * A variable declared using this macro must be compile-time initialized 34 * and is as such placed into subsection of special section, .u_boot_list. 35 * The subsection is specified by the _section_[u,d] parameter, see below. 36 * The base name of the variable is _name, yet the actual variable is 37 * declared as concatenation of 38 * 39 * %_u_boot_list_ + @_section_u + _ + @_name 40 * 41 * which ensures name uniqueness. This variable shall never be refered 42 * directly though. 43 * 44 * Special precaution must be made when using this macro: 45 * 1) The _type must not contain the "static" keyword, otherwise the entry 46 * is not generated. 47 * 48 * 2) The @_section_u and @_section_d variables must match, the only difference 49 * is that in @_section_u is every dot "." character present in @_section_d 50 * replaced by a single underscore "_" character in @_section_u. The actual 51 * purpose of these parameters is to select proper subsection in the global 52 * .u_boot_list section. 53 * 54 * 3) In case a section is declared that contains some array elements AND a 55 * subsection of this section is declared and contains some elements, it is 56 * imperative that the elements are of the same type. 57 * 58 * 4) In case an outer section is declared that contains some array elements 59 * AND am inner subsection of this section is declared and contains some 60 * elements, then when traversing the outer section, even the elements of 61 * the inner sections are present in the array. 62 * 63 * Example: 64 * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub, cmd.sub) = { 65 * .x = 3, 66 * .y = 4, 67 * }; 68 */ 69 #define ll_entry_declare(_type, _name, _section_u, _section_d) \ 70 _type _u_boot_list_##_section_u##_##_name __attribute__(( \ 71 unused, aligned(4), \ 72 section(".u_boot_list."#_section_d"."#_name))) 73 74 /** 75 * ll_entry_start() - Point to first entry of linker-generated array 76 * @_type: Data type of the entry 77 * @_section_u: Subsection of u_boot_list in which this entry is placed 78 * (with underscores instead of dots) 79 * 80 * This function returns (_type *) pointer to the very first entry of a 81 * linker-generated array placed into subsection of .u_boot_list section 82 * specified by _section_u argument. 83 * 84 * Example: 85 * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub); 86 */ 87 #define ll_entry_start(_type, _section_u) \ 88 ({ \ 89 extern _type _u_boot_list_##_section_u##__start; \ 90 _type *_ll_result = &_u_boot_list_##_section_u##__start;\ 91 _ll_result; \ 92 }) 93 94 /** 95 * ll_entry_count() - Return the number of elements in linker-generated array 96 * @_type: Data type of the entry 97 * @_section_u: Subsection of u_boot_list in which this entry is placed 98 * (with underscores instead of dots) 99 * 100 * This function returns the number of elements of a linker-generated array 101 * placed into subsection of .u_boot_list section specified by _section_u 102 * argument. The result is of an unsigned int type. 103 * 104 * Example: 105 * int i; 106 * const unsigned int count = ll_entry_count(struct my_sub_cmd, cmd_sub); 107 * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub); 108 * for (i = 0; i < count; i++, msc++) 109 * printf("Entry %i, x=%i y=%i\n", i, msc->x, msc->y); 110 */ 111 #define ll_entry_count(_type, _section_u) \ 112 ({ \ 113 extern _type _u_boot_list_##_section_u##__start; \ 114 extern _type _u_boot_list_##_section_u##__end; \ 115 unsigned int _ll_result = \ 116 &_u_boot_list_##_section_u##__end - \ 117 &_u_boot_list_##_section_u##__start; \ 118 _ll_result; \ 119 }) 120 121 122 /** 123 * ll_entry_get() - Retrieve entry from linker-generated array by name 124 * @_type: Data type of the entry 125 * @_name: Name of the entry 126 * @_section_u: Subsection of u_boot_list in which this entry is placed 127 * (with underscores instead of dots) 128 * 129 * This function returns a pointer to a particular entry in LG-array 130 * identified by the subsection of u_boot_list where the entry resides 131 * and it's name. 132 * 133 * Example: 134 * ll_entry_declare(struct my_sub_cmd, my_sub_cmd, cmd_sub, cmd.sub) = { 135 * .x = 3, 136 * .y = 4, 137 * }; 138 * ... 139 * struct my_sub_cmd *c = ll_entry_get(struct my_sub_cmd, my_sub_cmd, cmd_sub); 140 */ 141 #define ll_entry_get(_type, _name, _section_u) \ 142 ({ \ 143 extern _type _u_boot_list_##_section_u##_##_name; \ 144 _type *_ll_result = &_u_boot_list_##_section_u##_##_name;\ 145 _ll_result; \ 146 }) 147 148 #endif /* __LINKER_LISTS_H__ */ 149