Skip to content

Commit 726e14e

Browse files
yonschnashif
authored andcommitted
doc: bindesc: Add documentation for binary descriptors
Add documentation for binary descriptors under "OS Services" Signed-off-by: Yonatan Schachter <[email protected]>
1 parent fd5fe8f commit 726e14e

File tree

4 files changed

+152
-0
lines changed

4 files changed

+152
-0
lines changed

doc/develop/west/zephyr-cmds.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,28 @@ Twister can then be invoked via west as follows::
185185

186186
west twister -help
187187
west twister -T tests/ztest/base
188+
189+
.. _west-bindesc:
190+
191+
Working with binary descriptors: ``west bindesc``
192+
*************************************************
193+
194+
The ``bindesc`` command allows users to read :ref:`binary descriptors<binary_descriptors>`
195+
of executable files. It currently supports ``.bin``, ``.hex``, ``.elf`` and ``.uf2`` files
196+
as input.
197+
198+
You can search for a specific descriptor in an image, for example::
199+
200+
west bindesc search KERNEL_VERSION_STRING build/zephyr/zephyr.bin
201+
202+
You can search for a custom descriptor by type and ID, for example::
203+
204+
west bindesc custom_search STR 0x200 build/zephyr/zephyr.bin
205+
206+
You can dump all of the descriptors in an image using::
207+
208+
west bindesc dump build/zephyr/zephyr.bin
209+
210+
You can list all known standard descriptor names using::
211+
212+
west bindesc list
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
.. _binary_descriptors:
2+
3+
Binary Descriptors
4+
##################
5+
6+
Binary Descriptors are constant data objects storing information about the binary executable.
7+
Unlike "regular" constants, binary descriptors are linked to a known offset in the binary, making
8+
them accesible to other programs, such as a different image running on the same device or a host tool.
9+
A few examples of constants that would make useful binary descriptors are: kernel version, app version,
10+
build time, compiler version, environment variables, compiling host name, etc.
11+
12+
Binary descriptors are created by using the ``DEFINE_BINDESC_*`` macros. For example:
13+
14+
.. code-block:: c
15+
16+
#include <zephyr/bindesc.h>
17+
18+
BINDESC_STR_DEFINE(my_string, 2, "Hello world!"); // Unique ID is 2
19+
20+
``my_string`` could then be accessed using:
21+
22+
.. code-block:: c
23+
24+
printk("my_string: %s\n", BINDESC_GET_STR(my_string));
25+
26+
But it could also be retrieved by ``west bindesc``:
27+
28+
.. code-block:: bash
29+
30+
$ west bindesc custom_search STR 2 build/zephyr/zephyr.bin
31+
"Hello world!"
32+
33+
Internals
34+
*********
35+
Binary descriptors are implemented with a TLV (tag, length, value) header linked
36+
to a known offset in the binary image. This offset may vary between architectures,
37+
but generally the descriptors are linked as close to the beginning of the image as
38+
possible. In architectures where the image must begin with a vector table (such as
39+
ARM), the descriptors are linked right after the vector table. The reset vector points
40+
to the beginning of the text section, which is after the descriptors. In architectures
41+
where the image must begin with executable code (e.g. x86), a jump instruction is injected at
42+
the beginning of the image, in order to skip over the binary descriptors, which are right
43+
after the jump instruction.
44+
45+
Each tag is a 16 bit unsigned integer, where the most significant nibble (4 bits) is the type
46+
(currently uint, string or bytes), and the rest is the ID. The ID is globally unique to each
47+
descriptor. For example, the ID of the app version string is ``0x800``, and a string
48+
is denoted by 0x1, making the app version tag ``0x1800``. The length is a 16 bit
49+
number equal to the length of the data in bytes. The data is the actual descriptor
50+
value. All binary descriptor numbers (magic, tags, uints) are laid out in memory
51+
in the endianness native to the SoC. ``west bindesc`` assumes little endian by default,
52+
so if the image belongs to a big endian SoC, the appropriate flag should be given to the
53+
tool.
54+
55+
The binary descriptor header starts with the magic number ``0xb9863e5a7ea46046``. It's followed
56+
by the TLVs, and ends with the ``DESCRIPTORS_END`` (``0xffff``) tag. The tags are
57+
always aligned to 32 bits. If the value of the previous descriptor had a non-aligned
58+
length, zero padding will be added to ensure that the current tag is aligned.
59+
60+
Putting it all together, here is what the example above would look like in memory
61+
(of a little endian SoC):
62+
63+
.. code-block::
64+
65+
46 60 a4 7e 5a 3e 86 b9 02 10 0d 00 48 65 6c 6c 6f 20 77 6f 72 6c 64 21 00 00 00 00 ff ff
66+
| magic | tag |length| H e l l o w o r l d ! | pad | end |
67+
68+
Usage
69+
*****
70+
Binary descriptors are always created by the ``BINDESC_*_DEFINE`` macros. As shown in
71+
the example above, a descriptor can be generated from any string or integer, with any
72+
ID. However, it is recommended to comply with the standard tags defined in
73+
``include/zephyr/bindesc.h``, as that would have the following benefits:
74+
75+
1. The ``west bindesc`` tool would be able to recognize what the descriptor means and
76+
print a meaningful tag
77+
2. It would enforce consistency between various apps from various sources
78+
3. It allows upstream-ability of descriptor generation (see Standard Descriptors)
79+
80+
To define a descriptor with a standard tag, just use the tags included from ``bindesc.h``:
81+
82+
.. code-block:: c
83+
84+
#include <zephyr/bindesc.h>
85+
86+
BINDESC_STR_DEFINE(app_version, BINDESC_ID_APP_VERSION_STRING, "1.2.3");
87+
88+
Standard Descriptors
89+
====================
90+
Some descriptors might be trivial to implement, and could therefore be implemented
91+
in a standard way in upstream Zephyr. These could then be enabled via Kconfig, instead
92+
of requiring every user to reimplement them. These include build times, kernel version,
93+
and host info. For example, to add the build date and time as a string, the following
94+
configs should be enabled:
95+
96+
.. code-block:: kconfig
97+
98+
# Enable binary descriptors
99+
CONFIG_BINDESC=y
100+
101+
# Enable definition of binary descriptors
102+
CONFIG_BINDESC_DEFINE=y
103+
104+
# Enable default build time binary descriptors
105+
CONFIG_BINDESC_DEFINE_BUILD_TIME=y
106+
CONFIG_BINDESC_BUILD_DATE_TIME_STRING=y
107+
108+
To avoid collisions with user defined descriptors, the standard descriptors were alloted
109+
the range between ``0x800-0xfff``. This leaves ``0x000-0x7ff`` to users.
110+
For more information read the ``help`` sections of these Kconfig symbols.
111+
By convention, each Kconfig symbol corresponds to a binary descriptor whose
112+
name is the Kconfig name (with ``CONFIG_BINDESC_`` removed) in lower case. For example,
113+
``CONFIG_BINDESC_KERNEL_VERSION_STRING`` creates a descriptor that can be
114+
accessed using ``BINDESC_GET_STR(kernel_version_string)``.
115+
116+
west bindesc tool
117+
=================
118+
``west`` is able to parse and display binary descriptors from a given executable image.
119+
120+
For more information refer to ``west bindesc --help`` or the :ref:`documentation<west-bindesc>`.
121+
122+
API Reference
123+
*************
124+
125+
.. doxygengroup:: bindesc_define

doc/services/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ OS Services
77
:maxdepth: 1
88

99

10+
binary_descriptors/index.rst
1011
crypto/index
1112
debugging/index.rst
1213
device_mgmt/index

scripts/ci/check_compliance.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,7 @@ def check_no_undef_outside_kconfig(self, kconf):
617617
# visible to compliance.
618618
"BOOT_ENCRYPTION_KEY_FILE", # Used in sysbuild
619619
"BOOT_ENCRYPT_IMAGE", # Used in sysbuild
620+
"BINDESC_", # Used in documentation as a prefix
620621
"BOOT_UPGRADE_ONLY", # Used in example adjusting MCUboot config, but
621622
# symbol is defined in MCUboot itself.
622623
"BOOT_SERIAL_BOOT_MODE", # Used in (sysbuild-based) test/

0 commit comments

Comments
 (0)