|
| 1 | +.. _doc_fw_info: |
| 2 | + |
| 3 | +Firmware information |
| 4 | +#################### |
| 5 | + |
| 6 | +The firmware information module (``fw_info``) provides externally readable metadata about a firmware image. |
| 7 | +This information is located at a specific offset in the image. |
| 8 | +In addition, the module provides code to read such information. |
| 9 | + |
| 10 | +Purpose |
| 11 | +******* |
| 12 | + |
| 13 | +The purpose of the firmware information is to allow other images such as bootloaders, or infrastructure such as firmware servers, to gain information about the firmware image. |
| 14 | + |
| 15 | +The firmware information structure has a 12-byte magic header and a verified binary layout to ensure that the format is portable and identifiable. |
| 16 | +It must be located at one of three offsets from the start of the image: 0x200, 0x400, or 0x800. |
| 17 | +The reason that the structure is not located at 0x00 is that this can be problematic in some use cases, such as when the vector table must be located at 0x00. |
| 18 | + |
| 19 | +These rules make it simple to retrieve the information by checking for each possible offset (0x200, 0x400, 0x800) if the first 12 bytes match the magic value. |
| 20 | +If they do, the information can be retrieved according to the definition in :c:type:`fw_info`. |
| 21 | + |
| 22 | +Information structure |
| 23 | +********************* |
| 24 | + |
| 25 | +The information structure contains a minimal set of information that allows other code to reason about the firmware with no other information available. |
| 26 | +It includes the following information: |
| 27 | + |
| 28 | +* The size of the firmware image. |
| 29 | +* The single, monotonically increasing version number of the image. |
| 30 | +* The address through which to boot into the firmware (the vector table address). |
| 31 | + This address is not necessarily the start of the image. |
| 32 | + |
| 33 | +Additionally, there is information for exchanging arbitrary data: |
| 34 | + |
| 35 | +* Application Binary Interface (ABI) getter (:cpp:member:`abi_out`) |
| 36 | +* Pointer to ABI getter (:cpp:member:`abi_in`) |
| 37 | + |
| 38 | +.. _doc_fw_info_abi: |
| 39 | + |
| 40 | +ABIs |
| 41 | +**** |
| 42 | + |
| 43 | +The firmware information structure allows for exchange of arbitrary tagged and versioned interfaces called Application Binary Interfaces (ABIs). |
| 44 | + |
| 45 | +An ABI structure is a structure consisting of a header followed by arbitrary data. |
| 46 | +The header consists of the following information: |
| 47 | + |
| 48 | +* ABI ID (uniquely identifies the ABI) |
| 49 | +* ABI version (single, monotonically increasing version number for the ABI with this ID) |
| 50 | +* ABI flags (32 individual bits for indicating the particulars of the ABI) |
| 51 | +* ABI length (length of the following data) |
| 52 | + |
| 53 | +To retrieve an ABI, a firmware image calls another firmware image's ABI getter. |
| 54 | +Every image must provide an ABI getter (:cpp:member:`abi_out`) that other images can use to retrieve its ABIs. |
| 55 | +This ABI getter is a function pointer that retrieves ABI structs (or rather pointers to ABI structs). |
| 56 | + |
| 57 | +In addition, every image can access other ABIs through a second ABI getter (:cpp:member:`abi_in`). |
| 58 | +This ABI getter must be provided when booting the image. |
| 59 | +In other words, an image should expect its :cpp:member:`abi_in` ABI getter to be filled at the time it boots, and will not touch it during booting. |
| 60 | +After booting, an image can call :cpp:member:`abi_in` to retrieve ABIs from the image or images that booted it without knowing where they are located. |
| 61 | + |
| 62 | +Each image can provide multiple ABIs. |
| 63 | +An ABI getter function takes an index, and each index from 0 to *n* must return a different ABI, given that the image provides *n* ABIs with the same ID. |
| 64 | + |
| 65 | +Typically, the actual ABI will be a function pointer (or a list of function pointers), but the data can be anything, though it should be considered read-only. |
| 66 | +The reason for making the ABI getters function pointers instead of pointing to a list of ABIs is to allow dynamic creation of ABI lists without using RAM. |
| 67 | + |
| 68 | +Usage |
| 69 | +***** |
| 70 | + |
| 71 | +To locate and verify firmware info structures, use :cpp:func:`fw_info_find` and :cpp:func:`fw_info_check`, respectively. |
| 72 | + |
| 73 | +To find an ABI with a given version and flags, call :cpp:func:`fw_info_abi_find`. |
| 74 | +This function calls :cpp:member:`abi_in` under the hood, checks the ABI's version against the allowed range, and checks that it has all the flags set. |
| 75 | + |
| 76 | +To populate an image's :cpp:member:`abi_in` (before booting the image), the booting image should call :cpp:func:`fw_info_abi_provide` with the other image's firmware information structure. |
| 77 | +Note that if the booting (current) firmware image and the booted image's RAM overlap, :cpp:func:`fw_info_abi_provide` will corrupt the current firmware's RAM. |
| 78 | +This is ok if it is done immediately before booting the other image, thus after it has performed its last RAM access. |
| 79 | + |
| 80 | +Creating ABIs |
| 81 | +************* |
| 82 | + |
| 83 | +To create an ABI, complete the following steps: |
| 84 | + |
| 85 | +1. Declare a new struct type that starts with the :c:type:`fw_info_abi` struct: |
| 86 | + |
| 87 | + .. code-block:: c |
| 88 | +
|
| 89 | + struct my_abi { |
| 90 | + struct fw_info_abi header; |
| 91 | + struct { |
| 92 | + /* Actual ABI/data goes here. */ |
| 93 | + } abi; |
| 94 | + }; |
| 95 | +
|
| 96 | +#. Use the :c:macro:`__ext_abi` macro to initialize the ABI struct in an arbitrary location. |
| 97 | + :c:macro:`__ext_abi` will automatically include the ABI in the list provided via :cpp:func:`fw_info_abi_provide`. |
| 98 | + |
| 99 | + .. code-block:: c |
| 100 | +
|
| 101 | + __ext_abi(struct my_abi, my_abi) = { |
| 102 | + .header = FW_INFO_ABI_INIT(MY_ABI_ID, |
| 103 | + CONFIG_MY_ABI_FLAGS, |
| 104 | + CONFIG_MY_ABI_VER, |
| 105 | + sizeof(struct my_abi)), |
| 106 | + .abi = { |
| 107 | + /* ABI initialization goes here. */ |
| 108 | + } |
| 109 | + }; |
| 110 | +
|
| 111 | +#. To include function pointers in your ABI, call the :c:macro:`EXT_ABI_FUNCTION` macro to forward-declare the function and create a typedef for the function pointer: |
| 112 | + |
| 113 | + .. code-block:: c |
| 114 | +
|
| 115 | + EXT_ABI_FUNCTION(int, my_abi_foo, bool arg1, int *arg2); |
| 116 | +
|
| 117 | +
|
| 118 | +
|
| 119 | +API documentation |
| 120 | +***************** |
| 121 | + |
| 122 | +| Header file: :file:`include/fw_info.h` |
| 123 | +| Source files: :file:`subsys/fw_info/` |
| 124 | +
|
| 125 | +.. doxygengroup:: fw_info |
| 126 | + :project: nrf |
| 127 | + :members: |
0 commit comments