|
| 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 |
0 commit comments