summaryrefslogtreecommitdiffstats
path: root/include/linker_lists.h
blob: 0b405d78ea34df1c528fbc4e24ed2aad756ac4a2 (plain)
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
/*
 * include/linker_lists.h
 *
 * Implementation of linker-generated arrays
 *
 * Copyright (C) 2012 Marek Vasut <marex@denx.de>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 */
#ifndef __LINKER_LISTS_H__
#define __LINKER_LISTS_H__

/**
 * ll_entry_declare() - Declare linker-generated array entry
 * @_type:	Data type of the entry
 * @_name:	Name of the entry
 * @_section_u:	Subsection of u_boot_list in which this entry is placed
 *		(with underscores instead of dots, for name concatenation)
 * @_section_d:	Subsection of u_boot_list in which this entry is placed
 *		(with dots, for section concatenation)
 *
 * 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
 * and is as such placed into subsection of special section, .u_boot_list.
 * The subsection is specified by the _section_[u,d] parameter, see below.
 * The base name of the variable is _name, yet the actual variable is
 * declared as concatenation of
 *
 *   %_u_boot_list_ + @_section_u + _ + @_name
 *
 * which ensures name uniqueness. This variable shall never be refered
 * directly though.
 *
 * Special precaution must be made when using this macro:
 * 1) The _type must not contain the "static" keyword, otherwise the entry
 *    is not generated.
 *
 * 2) The @_section_u and @_section_d variables must match, the only difference
 *    is that in @_section_u is every dot "." character present in @_section_d
 *    replaced by a single underscore "_" character in @_section_u. The actual
 *    purpose of these parameters is to select proper subsection in the global
 *    .u_boot_list section.
 *
 * 3) 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.
 *
 * 4) In case an outer section is declared that contains some array elements
 *    AND am 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, cmd.sub) = {
 *         .x = 3,
 *         .y = 4,
 * };
 */
#define ll_entry_declare(_type, _name, _section_u, _section_d)		\
	_type _u_boot_list_##_section_u##_##_name __attribute__((	\
			unused,	aligned(4),				\
			section(".u_boot_list."#_section_d"."#_name)))

/**
 * ll_entry_start() - Point to first entry of linker-generated array
 * @_type:	Data type of the entry
 * @_section_u:	Subsection of u_boot_list in which this entry is placed
 *		(with underscores instead of dots)
 *
 * 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 _section_u argument.
 *
 * Example:
 * struct my_sub_cmd *msc = ll_entry_start(struct my_sub_cmd, cmd_sub);
 */
#define ll_entry_start(_type, _section_u)				\
	({								\
		extern _type _u_boot_list_##_section_u##__start;	\
		_type *_ll_result = &_u_boot_list_##_section_u##__start;\
		_ll_result;						\
	})

/**
 * ll_entry_count() - Return the number of elements in linker-generated array
 * @_type:	Data type of the entry
 * @_section_u:	Subsection of u_boot_list in which this entry is placed
 *		(with underscores instead of dots)
 *
 * This function returns the number of elements of a linker-generated array
 * placed into subsection of .u_boot_list section specified by _section_u
 * 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, _section_u)				\
	({								\
		extern _type _u_boot_list_##_section_u##__start;	\
		extern _type _u_boot_list_##_section_u##__end;		\
		unsigned int _ll_result =				\
			&_u_boot_list_##_section_u##__end -		\
			&_u_boot_list_##_section_u##__start;		\
		_ll_result;						\
	})


/**
 * ll_entry_get() - Retrieve entry from linker-generated array by name
 * @_type:	Data type of the entry
 * @_name:	Name of the entry
 * @_section_u:	Subsection of u_boot_list in which this entry is placed
 *		(with underscores instead of dots)
 *
 * This function returns a pointer to a particular entry in LG-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, 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, _section_u)				\
	({								\
		extern _type _u_boot_list_##_section_u##_##_name;	\
		_type *_ll_result = &_u_boot_list_##_section_u##_##_name;\
		_ll_result;						\
	})

#endif	/* __LINKER_LISTS_H__ */
OpenPOWER on IntegriCloud