Skip to content

Commit 5508b17

Browse files
yonschnashif
authored andcommitted
bindesc: Add initial support for binary descriptor definition
Binary descriptors are data objects stored at a known location of a binary image. They can be read by an external tool or image, and are used mostly for build information: version, build time, host information, etc. This commit adds initial support for defining such descriptors. Signed-off-by: Yonatan Schachter <[email protected]>
1 parent a7df77c commit 5508b17

14 files changed

+883
-0
lines changed

include/zephyr/bindesc.h

Lines changed: 398 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,398 @@
1+
/*
2+
* Copyright (c) 2023 Yonatan Schachter
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#ifndef ZEPHYR_INCLUDE_ZEPHYR_BINDESC_H_
8+
#define ZEPHYR_INCLUDE_ZEPHYR_BINDESC_H_
9+
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif /* __cplusplus */
13+
14+
/*
15+
* Corresponds to the definitions in scripts/west_commands/bindesc.py.
16+
* Do not change without syncing the definitions in both files!
17+
*/
18+
#define BINDESC_MAGIC 0xb9863e5a7ea46046
19+
#define BINDESC_ALIGNMENT 4
20+
#define BINDESC_TYPE_UINT 0x0
21+
#define BINDESC_TYPE_STR 0x1
22+
#define BINDESC_TYPE_BYTES 0x2
23+
#define BINDESC_TYPE_DESCRIPTORS_END 0xf
24+
25+
/**
26+
* @brief Binary Descriptor Definition
27+
* @defgroup bindesc_define Bindesc Define
28+
* @{
29+
*/
30+
31+
/*
32+
* Corresponds to the definitions in scripts/west_commands/bindesc.py.
33+
* Do not change without syncing the definitions in both files!
34+
*/
35+
36+
/** The app version string such as "1.2.3" */
37+
#define BINDESC_ID_APP_VERSION_STRING 0x800
38+
39+
/** The app version major such as 1 */
40+
#define BINDESC_ID_APP_VERSION_MAJOR 0x801
41+
42+
/** The app version minor such as 2 */
43+
#define BINDESC_ID_APP_VERSION_MINOR 0x802
44+
45+
/** The app version patchlevel such as 3 */
46+
#define BINDESC_ID_APP_VERSION_PATCHLEVEL 0x803
47+
48+
/** The app version number such as 0x10203 */
49+
#define BINDESC_ID_APP_VERSION_NUMBER 0x804
50+
51+
/** The kernel version string such as "3.4.0" */
52+
#define BINDESC_ID_KERNEL_VERSION_STRING 0x900
53+
54+
/** The kernel version major such as 3 */
55+
#define BINDESC_ID_KERNEL_VERSION_MAJOR 0x901
56+
57+
/** The kernel version minor such as 4 */
58+
#define BINDESC_ID_KERNEL_VERSION_MINOR 0x902
59+
60+
/** The kernel version patchlevel such as 0 */
61+
#define BINDESC_ID_KERNEL_VERSION_PATCHLEVEL 0x903
62+
63+
/** The kernel version number such as 0x30400 */
64+
#define BINDESC_ID_KERNEL_VERSION_NUMBER 0x904
65+
66+
/** The year the image was compiled in */
67+
#define BINDESC_ID_BUILD_TIME_YEAR 0xa00
68+
69+
/** The month of the year the image was compiled in */
70+
#define BINDESC_ID_BUILD_TIME_MONTH 0xa01
71+
72+
/** The day of the month the image was compiled in */
73+
#define BINDESC_ID_BUILD_TIME_DAY 0xa02
74+
75+
/** The hour of the day the image was compiled in */
76+
#define BINDESC_ID_BUILD_TIME_HOUR 0xa03
77+
78+
/** The minute the image was compiled in */
79+
#define BINDESC_ID_BUILD_TIME_MINUTE 0xa04
80+
81+
/** The second the image was compiled in */
82+
#define BINDESC_ID_BUILD_TIME_SECOND 0xa05
83+
84+
/** The UNIX time (seconds since midnight of 1970/01/01) the image was compiled in */
85+
#define BINDESC_ID_BUILD_TIME_UNIX 0xa06
86+
87+
/** The date and time of compilation such as "2023/02/05 00:07:04" */
88+
#define BINDESC_ID_BUILD_DATE_TIME_STRING 0xa07
89+
90+
/** The date of compilation such as "2023/02/05" */
91+
#define BINDESC_ID_BUILD_DATE_STRING 0xa08
92+
93+
/** The time of compilation such as "00:07:04" */
94+
#define BINDESC_ID_BUILD_TIME_STRING 0xa09
95+
96+
/** The name of the host that compiled the image */
97+
#define BINDESC_ID_HOST_NAME 0xb00
98+
99+
/** The C compiler name */
100+
#define BINDESC_ID_C_COMPILER_NAME 0xb01
101+
102+
/** The C compiler version */
103+
#define BINDESC_ID_C_COMPILER_VERSION 0xb02
104+
105+
/** The C++ compiler name */
106+
#define BINDESC_ID_CXX_COMPILER_NAME 0xb03
107+
108+
/** The C++ compiler version */
109+
#define BINDESC_ID_CXX_COMPILER_VERSION 0xb04
110+
111+
#define BINDESC_TAG_DESCRIPTORS_END BINDESC_TAG(DESCRIPTORS_END, 0x0fff)
112+
113+
/**
114+
* @cond INTERNAL_HIDDEN
115+
*/
116+
117+
/*
118+
* Utility macro to generate a tag from a type and an ID
119+
*
120+
* type - Type of the descriptor, UINT, STR or BYTES
121+
* id - Unique ID for the descriptor, must fit in 12 bits
122+
*/
123+
#define BINDESC_TAG(type, id) ((BINDESC_TYPE_##type & 0xf) << 12 | (id & 0x0fff))
124+
125+
/**
126+
* @endcond
127+
*/
128+
129+
#if !IS_ENABLED(_LINKER)
130+
131+
#include <zephyr/sys/byteorder.h>
132+
133+
/**
134+
* @cond INTERNAL_HIDDEN
135+
*/
136+
137+
/*
138+
* Utility macro to get the name of a bindesc entry
139+
*/
140+
#define BINDESC_NAME(name) bindesc_entry_##name
141+
142+
/* Convenience helper for declaring a binary descriptor entry. */
143+
#define __BINDESC_ENTRY_DEFINE(name) \
144+
__aligned(BINDESC_ALIGNMENT) const struct bindesc_entry BINDESC_NAME(name) \
145+
__in_section(_bindesc_entry, static, name) __used __noasan
146+
147+
/**
148+
* @endcond
149+
*/
150+
151+
/**
152+
* @brief Define a binary descriptor of type string.
153+
*
154+
* @details
155+
* Define a string that is registered in the binary descriptor header.
156+
* The defined string can be accessed using @ref BINDESC_GET_STR
157+
*
158+
* @note The defined string is not static, so its name must not collide with
159+
* any other symbol in the executable.
160+
*
161+
* @param name Name of the descriptor
162+
* @param id Unique ID of the descriptor
163+
* @param value A string value for the descriptor
164+
*/
165+
#define BINDESC_STR_DEFINE(name, id, value) \
166+
__BINDESC_ENTRY_DEFINE(name) = { \
167+
.tag = BINDESC_TAG(STR, id), \
168+
.len = (uint16_t)sizeof(value), \
169+
.data = value, \
170+
}
171+
172+
/**
173+
* @brief Define a binary descriptor of type uint.
174+
*
175+
* @details
176+
* Define an integer that is registered in the binary descriptor header.
177+
* The defined integer can be accessed using @ref BINDESC_GET_UINT
178+
*
179+
* @note The defined integer is not static, so its name must not collide with
180+
* any other symbol in the executable.
181+
*
182+
* @param name Name of the descriptor
183+
* @param id Unique ID of the descriptor
184+
* @param value An integer value for the descriptor
185+
*/
186+
#define BINDESC_UINT_DEFINE(name, id, value) \
187+
__BINDESC_ENTRY_DEFINE(name) = { \
188+
.tag = BINDESC_TAG(UINT, id), \
189+
.len = (uint16_t)sizeof(uint32_t), \
190+
.data = sys_uint32_to_array(value), \
191+
}
192+
193+
/**
194+
* @brief Define a binary descriptor of type bytes.
195+
*
196+
* @details
197+
* Define a uint8_t array that is registered in the binary descriptor header.
198+
* The defined array can be accessed using @ref BINDESC_GET_BYTES.
199+
* The value should be given as an array literal, wrapped in parentheses, for
200+
* example:
201+
*
202+
* BINDESC_BYTES_DEFINE(name, id, ({1, 2, 3, 4}));
203+
*
204+
* @note The defined array is not static, so its name must not collide with
205+
* any other symbol in the executable.
206+
*
207+
* @param name Name of the descriptor
208+
* @param id Unique ID of the descriptor
209+
* @param value A uint8_t array as data for the descriptor
210+
*/
211+
#define BINDESC_BYTES_DEFINE(name, id, value) \
212+
__BINDESC_ENTRY_DEFINE(name) = { \
213+
.tag = BINDESC_TAG(BYTES, id), \
214+
.len = (uint16_t)sizeof((uint8_t [])__DEBRACKET value), \
215+
.data = __DEBRACKET value, \
216+
}
217+
218+
/**
219+
* @brief Get the value of a string binary descriptor
220+
*
221+
* @details
222+
* Get the value of a string binary descriptor, previously defined by
223+
* BINDESC_STR_DEFINE.
224+
*
225+
* @param name Name of the descriptor
226+
*/
227+
#define BINDESC_GET_STR(name) BINDESC_NAME(name).data
228+
229+
/**
230+
* @brief Get the value of a uint binary descriptor
231+
*
232+
* @details
233+
* Get the value of a uint binary descriptor, previously defined by
234+
* BINDESC_UINT_DEFINE.
235+
*
236+
* @param name Name of the descriptor
237+
*/
238+
#define BINDESC_GET_UINT(name) *(uint32_t *)&(BINDESC_NAME(name).data)
239+
240+
/**
241+
* @brief Get the value of a bytes binary descriptor
242+
*
243+
* @details
244+
* Get the value of a string binary descriptor, previously defined by
245+
* BINDESC_BYTES_DEFINE. The returned value can be accessed as an array:
246+
*
247+
* for (size_t i = 0; i < BINDESC_GET_SIZE(name); i++)
248+
* BINDESC_GET_BYTES(name)[i];
249+
*
250+
* @param name Name of the descriptor
251+
*/
252+
#define BINDESC_GET_BYTES(name) BINDESC_NAME(name).data
253+
254+
/**
255+
* @brief Get the size of a binary descriptor
256+
*
257+
* @details
258+
* Get the size of a binary descriptor. This is particularly useful for
259+
* bytes binary descriptors where there's no null terminator.
260+
*
261+
* @param name Name of the descriptor
262+
*/
263+
#define BINDESC_GET_SIZE(name) BINDESC_NAME(name).len
264+
265+
/**
266+
* @}
267+
*/
268+
269+
/*
270+
* An entry of the binary descriptor header. Each descriptor is
271+
* described by one of these entries.
272+
*/
273+
struct bindesc_entry {
274+
/** Tag of the entry */
275+
uint16_t tag;
276+
/** Length of the descriptor data */
277+
uint16_t len;
278+
/** Value of the entry. This is either an integer or a string */
279+
uint8_t data[];
280+
} __packed;
281+
282+
/*
283+
* We're assuming that `struct bindesc_entry` has a specific layout in
284+
* memory, so it's worth making sure that the layout is really what we
285+
* think it is. If these assertions fail for your toolchain/platform,
286+
* please open a bug report.
287+
*/
288+
BUILD_ASSERT(offsetof(struct bindesc_entry, tag) == 0, "Incorrect memory layout");
289+
BUILD_ASSERT(offsetof(struct bindesc_entry, len) == 2, "Incorrect memory layout");
290+
BUILD_ASSERT(offsetof(struct bindesc_entry, data) == 4, "Incorrect memory layout");
291+
292+
#if IS_ENABLED(CONFIG_BINDESC_KERNEL_VERSION_STRING)
293+
extern const struct bindesc_entry BINDESC_NAME(kernel_version_string);
294+
#endif /* IS_ENABLED(CONFIG_BINDESC_KERNEL_VERSION_STRING) */
295+
296+
#if IS_ENABLED(CONFIG_BINDESC_KERNEL_VERSION_MAJOR)
297+
extern const struct bindesc_entry BINDESC_NAME(kernel_version_major);
298+
#endif /* IS_ENABLED(CONFIG_BINDESC_KERNEL_VERSION_MAJOR) */
299+
300+
#if IS_ENABLED(CONFIG_BINDESC_KERNEL_VERSION_MINOR)
301+
extern const struct bindesc_entry BINDESC_NAME(kernel_version_minor);
302+
#endif /* IS_ENABLED(CONFIG_BINDESC_KERNEL_VERSION_MINOR) */
303+
304+
#if IS_ENABLED(CONFIG_BINDESC_KERNEL_VERSION_PATCHLEVEL)
305+
extern const struct bindesc_entry BINDESC_NAME(kernel_version_patchlevel);
306+
#endif /* IS_ENABLED(CONFIG_BINDESC_KERNEL_VERSION_PATCHLEVEL) */
307+
308+
#if IS_ENABLED(CONFIG_BINDESC_KERNEL_VERSION_NUMBER)
309+
extern const struct bindesc_entry BINDESC_NAME(kernel_version_number);
310+
#endif /* IS_ENABLED(CONFIG_BINDESC_KERNEL_VERSION_NUMBER) */
311+
312+
#if IS_ENABLED(CONFIG_BINDESC_APP_VERSION_STRING)
313+
extern const struct bindesc_entry BINDESC_NAME(app_version_string);
314+
#endif /* IS_ENABLED(CONFIG_BINDESC_APP_VERSION_STRING) */
315+
316+
#if IS_ENABLED(CONFIG_BINDESC_APP_VERSION_MAJOR)
317+
extern const struct bindesc_entry BINDESC_NAME(app_version_major);
318+
#endif /* IS_ENABLED(CONFIG_BINDESC_APP_VERSION_MAJOR) */
319+
320+
#if IS_ENABLED(CONFIG_BINDESC_APP_VERSION_MINOR)
321+
extern const struct bindesc_entry BINDESC_NAME(app_version_minor);
322+
#endif /* IS_ENABLED(CONFIG_BINDESC_APP_VERSION_MINOR) */
323+
324+
#if IS_ENABLED(CONFIG_BINDESC_APP_VERSION_PATCHLEVEL)
325+
extern const struct bindesc_entry BINDESC_NAME(app_version_patchlevel);
326+
#endif /* IS_ENABLED(CONFIG_BINDESC_APP_VERSION_PATCHLEVEL) */
327+
328+
#if IS_ENABLED(CONFIG_BINDESC_APP_VERSION_NUMBER)
329+
extern const struct bindesc_entry BINDESC_NAME(app_version_number);
330+
#endif /* IS_ENABLED(CONFIG_BINDESC_APP_VERSION_NUMBER) */
331+
332+
#if IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_YEAR)
333+
extern const struct bindesc_entry BINDESC_NAME(build_time_year);
334+
#endif /* IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_YEAR) */
335+
336+
#if IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_MONTH)
337+
extern const struct bindesc_entry BINDESC_NAME(build_time_month);
338+
#endif /* IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_MONTH) */
339+
340+
#if IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_DAY)
341+
extern const struct bindesc_entry BINDESC_NAME(build_time_day);
342+
#endif /* IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_DAY) */
343+
344+
#if IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_HOUR)
345+
extern const struct bindesc_entry BINDESC_NAME(build_time_hour);
346+
#endif /* IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_HOUR) */
347+
348+
#if IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_MINUTE)
349+
extern const struct bindesc_entry BINDESC_NAME(build_time_minute);
350+
#endif /* IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_MINUTE) */
351+
352+
#if IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_SECOND)
353+
extern const struct bindesc_entry BINDESC_NAME(build_time_second);
354+
#endif /* IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_SECOND) */
355+
356+
#if IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_UNIX)
357+
extern const struct bindesc_entry BINDESC_NAME(build_time_unix);
358+
#endif /* IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_UNIX) */
359+
360+
#if IS_ENABLED(CONFIG_BINDESC_BUILD_DATE_TIME_STRING)
361+
extern const struct bindesc_entry BINDESC_NAME(build_date_time_string);
362+
#endif /* IS_ENABLED(CONFIG_BINDESC_BUILD_DATE_TIME_STRING) */
363+
364+
#if IS_ENABLED(CONFIG_BINDESC_BUILD_DATE_STRING)
365+
extern const struct bindesc_entry BINDESC_NAME(build_date_string);
366+
#endif /* IS_ENABLED(CONFIG_BINDESC_BUILD_DATE_STRING) */
367+
368+
#if IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_STRING)
369+
extern const struct bindesc_entry BINDESC_NAME(build_time_string);
370+
#endif /* IS_ENABLED(CONFIG_BINDESC_BUILD_TIME_STRING) */
371+
372+
#if IS_ENABLED(CONFIG_BINDESC_HOST_NAME)
373+
extern const struct bindesc_entry BINDESC_NAME(host_name);
374+
#endif /* IS_ENABLED(CONFIG_BINDESC_HOST_NAME) */
375+
376+
#if IS_ENABLED(CONFIG_BINDESC_C_COMPILER_NAME)
377+
extern const struct bindesc_entry BINDESC_NAME(c_compiler_name);
378+
#endif /* IS_ENABLED(CONFIG_BINDESC_C_COMPILER_NAME) */
379+
380+
#if IS_ENABLED(CONFIG_BINDESC_C_COMPILER_VERSION)
381+
extern const struct bindesc_entry BINDESC_NAME(c_compiler_version);
382+
#endif /* IS_ENABLED(CONFIG_BINDESC_C_COMPILER_VERSION) */
383+
384+
#if IS_ENABLED(CONFIG_BINDESC_CXX_COMPILER_NAME)
385+
extern const struct bindesc_entry BINDESC_NAME(cxx_compiler_name);
386+
#endif /* IS_ENABLED(CONFIG_BINDESC_CXX_COMPILER_NAME) */
387+
388+
#if IS_ENABLED(CONFIG_BINDESC_CXX_COMPILER_VERSION)
389+
extern const struct bindesc_entry BINDESC_NAME(cxx_compiler_version);
390+
#endif /* IS_ENABLED(CONFIG_BINDESC_CXX_COMPILER_VERSION) */
391+
392+
#endif /* !IS_ENABLED(_LINKER) */
393+
394+
#ifdef __cplusplus
395+
}
396+
#endif
397+
398+
#endif /* ZEPHYR_INCLUDE_ZEPHYR_BINDESC_H_ */

0 commit comments

Comments
 (0)