blob: 634453d421e55139b36a788ee00ecb80eb98344e [file] [log] [blame]
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -05001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2023, Linaro Limited
4 */
5
6#include <errno.h>
7#include <getopt.h>
8#include <limits.h>
9#include <stdio.h>
10#include <stdint.h>
11#include <stdlib.h>
12#include <string.h>
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -050013#include <unistd.h>
Sughosh Ganudf42d682024-03-22 16:27:28 +053014#include <generated/autoconf.h>
15#include <u-boot/crc.h>
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -050016#include <uuid/uuid.h>
17
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -050018typedef uint8_t u8;
19typedef int16_t s16;
20typedef uint16_t u16;
21typedef uint32_t u32;
22typedef uint64_t u64;
23
Sughosh Ganudf42d682024-03-22 16:27:28 +053024#undef CONFIG_FWU_NUM_BANKS
25#undef CONFIG_FWU_NUM_IMAGES_PER_BANK
26
27/* This will dynamically allocate the fwu_mdata */
28#define CONFIG_FWU_NUM_BANKS 0
29#define CONFIG_FWU_NUM_IMAGES_PER_BANK 0
30
31/* version 2 supports maximum of 4 banks */
32#define MAX_BANKS_V2 4
33
34#define BANK_INVALID (u8)0xFF
35#define BANK_ACCEPTED (u8)0xFC
36
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -050037#include <fwu_mdata.h>
38
39/* TODO: Endianness conversion may be required for some arch. */
40
Sughosh Ganudf42d682024-03-22 16:27:28 +053041static const char *opts_short = "b:i:a:p:v:gh";
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -050042
43static struct option options[] = {
44 {"banks", required_argument, NULL, 'b'},
45 {"images", required_argument, NULL, 'i'},
46 {"guid", required_argument, NULL, 'g'},
47 {"active-bank", required_argument, NULL, 'a'},
48 {"previous-bank", required_argument, NULL, 'p'},
Sughosh Ganudf42d682024-03-22 16:27:28 +053049 {"version", required_argument, NULL, 'v'},
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -050050 {"help", no_argument, NULL, 'h'},
51 {NULL, 0, NULL, 0},
52};
53
54static void print_usage(void)
55{
56 fprintf(stderr, "Usage: mkfwumdata [options] <UUIDs list> <output file>\n");
57 fprintf(stderr, "Options:\n"
58 "\t-i, --images <num> Number of images (mandatory)\n"
59 "\t-b, --banks <num> Number of banks (mandatory)\n"
Sughosh Ganudf42d682024-03-22 16:27:28 +053060 "\t-v, --version Metadata version (mandatory)\n"
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -050061 "\t-a, --active-bank <num> Active bank (default=0)\n"
62 "\t-p, --previous-bank <num> Previous active bank (default=active_bank - 1)\n"
63 "\t-g, --guid Use GUID instead of UUID\n"
64 "\t-h, --help print a help message\n"
65 );
66 fprintf(stderr, " UUIDs list syntax:\n"
67 "\t <location uuid>,<image type uuid>,<images uuid list>\n"
68 "\t images uuid list syntax:\n"
69 "\t img_uuid_00,img_uuid_01...img_uuid_0b,\n"
70 "\t img_uuid_10,img_uuid_11...img_uuid_1b,\n"
71 "\t ...,\n"
72 "\t img_uuid_i0,img_uuid_i1...img_uuid_ib,\n"
73 "\t where 'b' and 'i' are number of banks and number\n"
74 "\t of images in a bank respectively.\n"
75 );
76}
77
78struct fwu_mdata_object {
79 size_t images;
80 size_t banks;
81 size_t size;
Sughosh Ganudf42d682024-03-22 16:27:28 +053082 u8 version;
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -050083 struct fwu_mdata *mdata;
84};
85
86static int previous_bank, active_bank;
87static bool __use_guid;
88
Sughosh Ganudf42d682024-03-22 16:27:28 +053089static bool supported_mdata_version(unsigned long version)
90{
91 switch (version) {
92 case 1:
93 case 2:
94 return true;
95 default:
96 return false;
97 }
98}
99
100static struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks,
101 u8 version)
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500102{
103 struct fwu_mdata_object *mobj;
104
105 mobj = calloc(1, sizeof(*mobj));
106 if (!mobj)
107 return NULL;
108
Sughosh Ganudf42d682024-03-22 16:27:28 +0530109 if (version == 1) {
110 mobj->size = sizeof(struct fwu_mdata) +
111 (sizeof(struct fwu_image_entry) +
112 sizeof(struct fwu_image_bank_info) * banks) * images;
113 } else {
114 mobj->size = sizeof(struct fwu_mdata) +
115 sizeof(struct fwu_fw_store_desc) +
116 (sizeof(struct fwu_image_entry) +
117 sizeof(struct fwu_image_bank_info) * banks) * images;
118 }
119
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500120 mobj->images = images;
121 mobj->banks = banks;
Sughosh Ganudf42d682024-03-22 16:27:28 +0530122 mobj->version = version;
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500123
124 mobj->mdata = calloc(1, mobj->size);
125 if (!mobj->mdata) {
126 free(mobj);
127 return NULL;
128 }
129
130 return mobj;
131}
132
133static struct fwu_image_entry *
134fwu_get_image(struct fwu_mdata_object *mobj, size_t idx)
135{
136 size_t offset;
137
Sughosh Ganudf42d682024-03-22 16:27:28 +0530138 if (mobj->version == 1) {
139 offset = sizeof(struct fwu_mdata) +
140 (sizeof(struct fwu_image_entry) +
141 sizeof(struct fwu_image_bank_info) * mobj->banks) *
142 idx;
143 } else {
144 offset = sizeof(struct fwu_mdata) +
145 sizeof(struct fwu_fw_store_desc) +
146 (sizeof(struct fwu_image_entry) +
147 sizeof(struct fwu_image_bank_info) * mobj->banks) *
148 idx;
149 }
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500150
151 return (struct fwu_image_entry *)((char *)mobj->mdata + offset);
152}
153
154static struct fwu_image_bank_info *
155fwu_get_bank(struct fwu_mdata_object *mobj, size_t img_idx, size_t bnk_idx)
156{
157 size_t offset;
158
Sughosh Ganudf42d682024-03-22 16:27:28 +0530159 if (mobj->version == 1) {
160 offset = sizeof(struct fwu_mdata) +
161 (sizeof(struct fwu_image_entry) +
162 sizeof(struct fwu_image_bank_info) * mobj->banks) *
163 img_idx + sizeof(struct fwu_image_entry) +
164 sizeof(struct fwu_image_bank_info) * bnk_idx;
165 } else {
166 offset = sizeof(struct fwu_mdata) +
167 sizeof(struct fwu_fw_store_desc) +
168 (sizeof(struct fwu_image_entry) +
169 sizeof(struct fwu_image_bank_info) * mobj->banks) *
170 img_idx + sizeof(struct fwu_image_entry) +
171 sizeof(struct fwu_image_bank_info) * bnk_idx;
172 }
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500173
174 return (struct fwu_image_bank_info *)((char *)mobj->mdata + offset);
175}
176
177/**
178 * convert_uuid_to_guid() - convert UUID to GUID
179 * @buf: UUID binary
180 *
181 * UUID and GUID have the same data structure, but their binary
182 * formats are different due to the endianness. See lib/uuid.c.
183 * Since uuid_parse() can handle only UUID, this function must
184 * be called to get correct data for GUID when parsing a string.
185 *
186 * The correct data will be returned in @buf.
187 */
188static void convert_uuid_to_guid(unsigned char *buf)
189{
190 unsigned char c;
191
192 c = buf[0];
193 buf[0] = buf[3];
194 buf[3] = c;
195 c = buf[1];
196 buf[1] = buf[2];
197 buf[2] = c;
198
199 c = buf[4];
200 buf[4] = buf[5];
201 buf[5] = c;
202
203 c = buf[6];
204 buf[6] = buf[7];
205 buf[7] = c;
206}
207
208static int uuid_guid_parse(char *uuidstr, unsigned char *uuid)
209{
210 int ret;
211
212 ret = uuid_parse(uuidstr, uuid);
213 if (ret < 0)
214 return ret;
215
216 if (__use_guid)
217 convert_uuid_to_guid(uuid);
218
219 return ret;
220}
221
222static int
223fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj,
224 size_t idx, char *uuids)
225{
226 struct fwu_image_entry *image = fwu_get_image(mobj, idx);
227 struct fwu_image_bank_info *bank;
228 char *p = uuids, *uuid;
229 int i;
230
231 if (!image)
232 return -ENOENT;
233
234 /* Image location UUID */
235 uuid = strsep(&p, ",");
236 if (!uuid)
237 return -EINVAL;
238
239 if (strcmp(uuid, "0") &&
Sughosh Ganudf42d682024-03-22 16:27:28 +0530240 uuid_guid_parse(uuid, (unsigned char *)&image->location_guid) < 0)
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500241 return -EINVAL;
242
243 /* Image type UUID */
244 uuid = strsep(&p, ",");
245 if (!uuid)
246 return -EINVAL;
247
Sughosh Ganudf42d682024-03-22 16:27:28 +0530248 if (uuid_guid_parse(uuid, (unsigned char *)&image->image_type_guid) < 0)
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500249 return -EINVAL;
250
251 /* Fill bank image-UUID */
252 for (i = 0; i < mobj->banks; i++) {
253 bank = fwu_get_bank(mobj, idx, i);
254 if (!bank)
255 return -ENOENT;
256 bank->accepted = 1;
257 uuid = strsep(&p, ",");
258 if (!uuid)
259 return -EINVAL;
260
261 if (strcmp(uuid, "0") &&
Sughosh Ganudf42d682024-03-22 16:27:28 +0530262 uuid_guid_parse(uuid, (unsigned char *)&bank->image_guid) < 0)
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500263 return -EINVAL;
264 }
265 return 0;
266}
267
Sughosh Ganudf42d682024-03-22 16:27:28 +0530268#if defined(CONFIG_FWU_MDATA_V1)
269static void fwu_fill_version_specific_mdata(struct fwu_mdata_object *mobj)
270{
271}
272#else
273static void fwu_fill_version_specific_mdata(struct fwu_mdata_object *mobj)
274{
275 int i;
276 struct fwu_fw_store_desc *fw_desc;
277 struct fwu_mdata *mdata = mobj->mdata;
278
279 mdata->metadata_size = mobj->size;
280 mdata->desc_offset = sizeof(struct fwu_mdata);
281
282 for (i = 0; i < MAX_BANKS_V2; i++)
283 mdata->bank_state[i] = i < mobj->banks ?
284 BANK_ACCEPTED : BANK_INVALID;
285
286 fw_desc = (struct fwu_fw_store_desc *)((u8 *)mdata + sizeof(*mdata));
287 fw_desc->num_banks = mobj->banks;
288 fw_desc->num_images = mobj->images;
289 fw_desc->img_entry_size = sizeof(struct fwu_image_entry) +
290 (sizeof(struct fwu_image_bank_info) * mobj->banks);
291 fw_desc->bank_info_entry_size =
292 sizeof(struct fwu_image_bank_info);
293}
294#endif /* CONFIG_FWU_MDATA_V1 */
295
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500296/* Caller must ensure that @uuids[] has @mobj->images entries. */
297static int fwu_parse_fill_uuids(struct fwu_mdata_object *mobj, char *uuids[])
298{
299 struct fwu_mdata *mdata = mobj->mdata;
300 int i, ret;
301
Sughosh Ganudf42d682024-03-22 16:27:28 +0530302 mdata->version = mobj->version;
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500303 mdata->active_index = active_bank;
304 mdata->previous_active_index = previous_bank;
305
Sughosh Ganudf42d682024-03-22 16:27:28 +0530306 fwu_fill_version_specific_mdata(mobj);
307
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500308 for (i = 0; i < mobj->images; i++) {
309 ret = fwu_parse_fill_image_uuid(mobj, i, uuids[i]);
310 if (ret < 0)
311 return ret;
312 }
313
314 mdata->crc32 = crc32(0, (const unsigned char *)&mdata->version,
315 mobj->size - sizeof(uint32_t));
316
317 return 0;
318}
319
320static int
Sughosh Ganudf42d682024-03-22 16:27:28 +0530321fwu_make_mdata(size_t images, size_t banks, u8 version, char *uuids[],
322 char *output)
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500323{
324 struct fwu_mdata_object *mobj;
325 FILE *file;
326 int ret;
327
Sughosh Ganudf42d682024-03-22 16:27:28 +0530328 mobj = fwu_alloc_mdata(images, banks, version);
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500329 if (!mobj)
330 return -ENOMEM;
331
332 ret = fwu_parse_fill_uuids(mobj, uuids);
333 if (ret < 0)
334 goto done_make;
335
336 file = fopen(output, "w");
337 if (!file) {
338 ret = -errno;
339 goto done_make;
340 }
341
Sughosh Ganud99127a2024-03-22 16:27:15 +0530342 ret = fwrite(mobj->mdata, 1, mobj->size, file);
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500343 if (ret != mobj->size)
344 ret = -errno;
345 else
346 ret = 0;
347
348 fclose(file);
349
350done_make:
351 free(mobj->mdata);
352 free(mobj);
353
354 return ret;
355}
356
357int main(int argc, char *argv[])
358{
Sughosh Ganudf42d682024-03-22 16:27:28 +0530359 unsigned long banks = 0, images = 0, version = 0;
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500360 int c, ret;
361
362 /* Explicitly initialize defaults */
363 active_bank = 0;
364 __use_guid = false;
365 previous_bank = INT_MAX;
366
367 do {
368 c = getopt_long(argc, argv, opts_short, options, NULL);
369 switch (c) {
370 case 'h':
371 print_usage();
372 return 0;
373 case 'b':
374 banks = strtoul(optarg, NULL, 0);
375 break;
376 case 'i':
377 images = strtoul(optarg, NULL, 0);
378 break;
379 case 'g':
380 __use_guid = true;
381 break;
382 case 'p':
383 previous_bank = strtoul(optarg, NULL, 0);
384 break;
385 case 'a':
386 active_bank = strtoul(optarg, NULL, 0);
387 break;
Sughosh Ganudf42d682024-03-22 16:27:28 +0530388 case 'v':
389 version = strtoul(optarg, NULL, 0);
390 break;
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500391 }
392 } while (c != -1);
393
394 if (!banks || !images) {
395 fprintf(stderr, "Error: The number of banks and images must not be 0.\n");
396 return -EINVAL;
397 }
398
Sughosh Ganudf42d682024-03-22 16:27:28 +0530399 if (!version || !supported_mdata_version(version)) {
400 fprintf(stderr, "Error: Version value can only be either 1 or 2, not %ld.\n",
401 version);
402 return -EINVAL;
403 }
404
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500405 /* This command takes UUIDs * images and output file. */
406 if (optind + images + 1 != argc) {
407 fprintf(stderr, "Error: UUID list or output file is not specified or too much.\n");
408 print_usage();
409 return -ERANGE;
410 }
411
412 if (previous_bank == INT_MAX) {
413 /* set to the earlier bank in round-robin scheme */
414 previous_bank = active_bank > 0 ? active_bank - 1 : banks - 1;
415 }
416
Sughosh Ganudf42d682024-03-22 16:27:28 +0530417 ret = fwu_make_mdata(images, banks, (u8)version, argv + optind,
418 argv[argc - 1]);
Masami Hiramatsufdd56bf2023-05-31 00:29:24 -0500419 if (ret < 0)
420 fprintf(stderr, "Error: Failed to parse and write image: %s\n",
421 strerror(-ret));
422
423 return ret;
424}