Skip to content

Commit 2ca6e9c

Browse files
oyvindronningstadhakonfam
authored andcommitted
fw_info: Add documentation
Add .rst documentation for the module. Signed-off-by: Øyvind Rønningstad <[email protected]>
1 parent dd365fa commit 2ca6e9c

File tree

3 files changed

+159
-13
lines changed

3 files changed

+159
-13
lines changed

include/bl_validation.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
#ifndef BL_VALIDATION_H__
88
#define BL_VALIDATION_H__
99

10+
/*
11+
* The FW package will consist of (firmware | (padding) | validation_info),
12+
* where the firmware contains the firmware_info at a predefined location. The
13+
* padding is present if the validation_info needs alignment. The
14+
* validation_info is not directly referenced from the firmware_info since the
15+
* validation_info doesn't actually have to be placed after the firmware.
16+
*/
17+
1018
#include <stdbool.h>
1119
#include <fw_info.h>
1220

include/fw_info.h

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,9 @@
77
#ifndef FW_INFO_H__
88
#define FW_INFO_H__
99

10-
/*
11-
* The package will consist of (firmware | (padding) | validation_info),
12-
* where the firmware contains the firmware_info at a predefined location. The
13-
* padding is present if the validation_info needs alignment. The
14-
* validation_info is not directly referenced from the firmware_info since the
15-
* validation_info doesn't actually have to be placed after the firmware.
16-
*
17-
* Putting the firmware info inside the firmware instead of in front of it
18-
* removes the need to consider the padding before the vector table of the
19-
* firmware. It will also likely make it easier to add all the info at compile
20-
* time.
21-
*/
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
2213

2314
#include <zephyr/types.h>
2415
#include <stddef.h>
@@ -30,6 +21,10 @@
3021
#include <pm_config.h>
3122
#endif
3223

24+
/** @defgroup fw_info Firmware info structure
25+
* @{
26+
*/
27+
3328
#define MAGIC_LEN_WORDS (CONFIG_FW_INFO_MAGIC_LEN / sizeof(u32_t))
3429

3530
struct fw_info_abi;
@@ -75,7 +70,9 @@ struct __packed fw_info {
7570
const fw_info_abi_getter abi_out;
7671
};
7772

78-
73+
/** @cond
74+
* Remove from doc building.
75+
*/
7976
#define OFFSET_CHECK(type, member, value) \
8077
BUILD_ASSERT_MSG(offsetof(type, member) == value, \
8178
#member " has wrong offset")
@@ -88,6 +85,9 @@ OFFSET_CHECK(struct fw_info, firmware_version,
8885
OFFSET_CHECK(struct fw_info, firmware_address,
8986
(CONFIG_FW_INFO_MAGIC_LEN + 8));
9087

88+
/** @endcond
89+
*/
90+
9191
/* For declaring this firmware's firmware info. */
9292
#define __fw_info Z_GENERIC_SECTION(.firmware_info) __attribute__((used)) const
9393

@@ -238,8 +238,13 @@ static inline const struct fw_info *fw_info_check(u32_t fw_info_addr)
238238
static const u32_t allowed_offsets[] = {FW_INFO_OFFSET0, FW_INFO_OFFSET1,
239239
FW_INFO_OFFSET2};
240240

241+
/** @cond
242+
* Remove from doc building.
243+
*/
241244
BUILD_ASSERT_MSG(ARRAY_SIZE(allowed_offsets) == FW_INFO_OFFSET_COUNT,
242245
"Mismatch in the number of allowed offsets.");
246+
/** @endcond
247+
*/
243248

244249
#if (FW_INFO_OFFSET_COUNT != 3) || ((CURRENT_OFFSET) != (FW_INFO_OFFSET0) && \
245250
(CURRENT_OFFSET) != (FW_INFO_OFFSET1) && \
@@ -306,4 +311,10 @@ const struct fw_info_abi *fw_info_abi_get(u32_t id, u32_t index);
306311
const struct fw_info_abi *fw_info_abi_find(u32_t id, u32_t flags,
307312
u32_t min_version, u32_t max_version);
308313

314+
/** @} */
315+
316+
#ifdef __cplusplus
317+
}
318+
#endif
319+
309320
#endif

include/fw_info.rst

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
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

Comments
 (0)