1.. _binary_descriptors: 2 3Binary Descriptors 4################## 5 6Binary Descriptors are constant data objects storing information about the binary executable. 7Unlike "regular" constants, binary descriptors are linked to a known offset in the binary, making 8them accessible to other programs, such as a different image running on the same device or a host tool. 9A few examples of constants that would make useful binary descriptors are: kernel version, app version, 10build time, compiler version, environment variables, compiling host name, etc. 11 12Binary 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 26But 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 33Internals 34********* 35Binary descriptors are implemented with a TLV (tag, length, value) header linked 36to a known offset in the binary image. This offset may vary between architectures, 37but generally the descriptors are linked as close to the beginning of the image as 38possible. In architectures where the image must begin with a vector table (such as 39ARM), the descriptors are linked right after the vector table. The reset vector points 40to the beginning of the text section, which is after the descriptors. In architectures 41where the image must begin with executable code (e.g. x86), a jump instruction is injected at 42the beginning of the image, in order to skip over the binary descriptors, which are right 43after the jump instruction. 44 45Each 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 47descriptor. For example, the ID of the app version string is ``0x800``, and a string 48is denoted by 0x1, making the app version tag ``0x1800``. The length is a 16 bit 49number equal to the length of the data in bytes. The data is the actual descriptor 50value. All binary descriptor numbers (magic, tags, uints) are laid out in memory 51in the endianness native to the SoC. ``west bindesc`` assumes little endian by default, 52so if the image belongs to a big endian SoC, the appropriate flag should be given to the 53tool. 54 55The binary descriptor header starts with the magic number ``0xb9863e5a7ea46046``. It's followed 56by the TLVs, and ends with the ``DESCRIPTORS_END`` (``0xffff``) tag. The tags are 57always aligned to 32 bits. If the value of the previous descriptor had a non-aligned 58length, zero padding will be added to ensure that the current tag is aligned. 59 60Putting 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 68Usage 69***** 70Binary descriptors are always created by the ``BINDESC_*_DEFINE`` macros. As shown in 71the example above, a descriptor can be generated from any string or integer, with any 72ID. 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 80To 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 88Standard Descriptors 89==================== 90Some descriptors might be trivial to implement, and could therefore be implemented 91in a standard way in upstream Zephyr. These could then be enabled via Kconfig, instead 92of requiring every user to reimplement them. These include build times, kernel version, 93and host info. For example, to add the build date and time as a string, the following 94configs 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 108To avoid collisions with user defined descriptors, the standard descriptors were allotted 109the range between ``0x800-0xfff``. This leaves ``0x000-0x7ff`` to users. 110For more information read the ``help`` sections of these Kconfig symbols. 111By convention, each Kconfig symbol corresponds to a binary descriptor whose 112name 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 114accessed using ``BINDESC_GET_STR(kernel_version_string)``. 115 116west bindesc tool 117================= 118``west`` is able to parse and display binary descriptors from a given executable image. 119 120For more information refer to ``west bindesc --help`` or the :ref:`documentation<west-bindesc>`. 121 122API Reference 123************* 124 125.. doxygengroup:: bindesc_define 126