forked from nrfconnect/sdk-nrf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfw_info_bare.h
238 lines (196 loc) · 6.67 KB
/
fw_info_bare.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/*
* Copyright (c) 2022 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
*/
#ifndef FW_INFO_BARE_H__
#define FW_INFO_BARE_H__
/** @defgroup fw_info_bare Firmware info structure definition and inline helpers
* @{
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <string.h>
#define MAGIC_LEN_WORDS (CONFIG_FW_INFO_MAGIC_LEN / sizeof(uint32_t))
/* The supported offsets for the fw_info struct. */
#define FW_INFO_OFFSET0 0x0
#define FW_INFO_OFFSET1 0x200
#define FW_INFO_OFFSET2 0x400
#define FW_INFO_OFFSET3 0x600
#define FW_INFO_OFFSET4 0x800
#define FW_INFO_OFFSET5 0xe00
#define FW_INFO_OFFSET6 0x1000
#define FW_INFO_OFFSET_COUNT 7
/**
* This struct serves as a header before an EXT_API.
*
* @details This header contains basic metadata about the EXT_API: A unique
* identifier, version and flags to be used for compatibility matching.
* The payload that comes after this header is completely
* implementation dependent for each EXT_API.
*
* @note How to use the EXT_API, such as the signatures of all the functions in
* the list must be unambiguous for an ID/version combination.
*/
struct __packed fw_info_ext_api {
/* Magic value to verify that the struct has the correct format.
* The magic value will change whenever the format changes.
*/
uint32_t magic[MAGIC_LEN_WORDS];
/* The length of this header plus everything after this header. Must be
* word-aligned.
*/
uint32_t ext_api_len;
/* The id of the EXT_API. */
uint32_t ext_api_id;
/* Flags specifying properties of the EXT_API. */
uint32_t ext_api_flags;
/* The version of this EXT_API. */
uint32_t ext_api_version;
};
/* Check and provide a pointer to a fw_info_ext_api structure.
*
* @return pointer if valid, NULL if not.
*/
static inline const struct fw_info_ext_api *fw_info_ext_api_check(
uint32_t ext_api_addr)
{
const struct fw_info_ext_api *ext_api;
const uint32_t ext_api_magic[] = {EXT_API_MAGIC};
ext_api = (const struct fw_info_ext_api *)(ext_api_addr);
if (memcmp(ext_api->magic, ext_api_magic, CONFIG_FW_INFO_MAGIC_LEN)
== 0) {
return ext_api;
}
return NULL;
}
/**
* A struct that is used to request an EXT_API.
*
* @details It contains a pointer to a non-initialized pointer that a previous
* boot stage will populate with a pointer to a compliant EXT_API. The
* EXT_API could be located in the boot stage itself, or in a third
* image. An EXT_API fulfills a request if the ID matches, all flags in
* the request are set in the EXT_API, and the version falls between
* the minimum and maximum (inclusive).
*
* The request is placed in the list of requests in the fw_info struct.
*
* @note If `required` is true, the image making the request will not function
* unless it has access to the EXT_API.
*
*/
struct __packed fw_info_ext_api_request {
/* The requested EXT_API. This struct defines the requested ID as well
* as the minimum required version and the flags that must be set.
*/
struct fw_info_ext_api request;
/* The maximum accepted version. */
uint32_t ext_api_max_version;
/* This EXT_API is required. I.e. having this EXT_API available is a
* hard requirement.
*/
uint32_t required;
/* Where to place a pointer to the EXT_API. */
const struct fw_info_ext_api **ext_api;
};
/**
* The top level firmware info struct.
*
* @details This is a data structure that is placed at a specific offset inside
* a firmware image so it can be consistently read by external parties.
* The specific offset makes it easy to find, and the magic value at
* the start guarantees that it contains data of a specific format.
*/
struct __packed fw_info {
/* Magic value to verify that the struct has the correct format.
* The magic value will change whenever the format changes.
*/
uint32_t magic[MAGIC_LEN_WORDS];
/* Total size of this fw_info struct including the EXT_API lists. */
uint32_t total_size;
/* Size of the firmware image code. */
uint32_t size;
/* Monotonically increasing version counter.*/
uint32_t version;
/* The address of the start of the image. */
uint32_t address;
/* The address of the boot point (vector table) of the firmware. */
uint32_t boot_address;
/* Value that can be modified to invalidate the firmware. Has the value
* CONFIG_FW_INFO_VALID_VAL when valid.
*/
uint32_t valid;
/* Reserved values (set to 0) */
uint32_t reserved[4];
/* The number of EXT_APIs in the @ref ext_apis list. */
uint32_t ext_api_num;
/* The number of EXT_API requests in the @ref ext_apis list. */
uint32_t ext_api_request_num;
/* A list of @ref ext_api_num EXT_APIs followed by @ref
* ext_api_request_num EXT_API requests. Since the entries have
* different lengths, the @ref ext_api_len of an entry is used to find
* the next entry. To get to the EXT_API requests, first iterate over
* all EXT_APIs.
*/
const struct fw_info_ext_api ext_apis[];
};
/* Check and provide a pointer to a firmware_info structure.
*
* @return pointer if valid, NULL if not.
*/
static inline const struct fw_info *fw_info_check(uint32_t fw_info_addr)
{
const struct fw_info *finfo;
const uint32_t fw_info_magic[] = {FIRMWARE_INFO_MAGIC};
finfo = (const struct fw_info *)(fw_info_addr);
if (memcmp(finfo->magic, fw_info_magic, CONFIG_FW_INFO_MAGIC_LEN)
== 0) {
return finfo;
}
return NULL;
}
/* The actual fw_info struct offset accounting for any space in front of the
* image, e.g. when there's a header.
*/
#define FW_INFO_CURRENT_OFFSET (CONFIG_FW_INFO_OFFSET + FW_INFO_VECTOR_OFFSET)
/* Array for run time usage. */
static const uint32_t fw_info_allowed_offsets[] = {
FW_INFO_OFFSET0, FW_INFO_OFFSET1,
FW_INFO_OFFSET2, FW_INFO_OFFSET3,
FW_INFO_OFFSET4, FW_INFO_OFFSET5,
FW_INFO_OFFSET6};
/** Search for the firmware_info structure inside the firmware.
*
* @param[in] firmware_address The start of the image. The function will search
* at the allowed offsets from firmware_address.
*
* @return A pointer to the fw_info struct if found. Otherwise NULL.
*/
static inline const struct fw_info *fw_info_find(uint32_t firmware_address)
{
const struct fw_info *finfo;
for (uint32_t i = 0; i < FW_INFO_OFFSET_COUNT; i++) {
finfo = fw_info_check(firmware_address +
fw_info_allowed_offsets[i]);
if (finfo) {
return finfo;
}
}
return NULL;
}
typedef bool (*fw_info_ext_api_provide_t)(const struct fw_info *fwinfo,
bool provide);
/**
* @brief Structure describing the EXT_API_PROVIDE EXT_API.
*/
struct ext_api_provide_ext_api {
fw_info_ext_api_provide_t ext_api_provide;
};
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* FW_INFO_BARE_H__ */