binman: doc: Remove incomplete sentence
[platform/kernel/u-boot.git] / tools / mkfwumdata.c
1 // 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>
13 #include <u-boot/crc.h>
14 #include <unistd.h>
15 #include <uuid/uuid.h>
16
17 /* This will dynamically allocate the fwu_mdata */
18 #define CONFIG_FWU_NUM_BANKS            0
19 #define CONFIG_FWU_NUM_IMAGES_PER_BANK  0
20
21 /* Since we can not include fwu.h, redefine version here. */
22 #define FWU_MDATA_VERSION               1
23
24 typedef uint8_t u8;
25 typedef int16_t s16;
26 typedef uint16_t u16;
27 typedef uint32_t u32;
28 typedef uint64_t u64;
29
30 #include <fwu_mdata.h>
31
32 /* TODO: Endianness conversion may be required for some arch. */
33
34 static const char *opts_short = "b:i:a:p:gh";
35
36 static struct option options[] = {
37         {"banks", required_argument, NULL, 'b'},
38         {"images", required_argument, NULL, 'i'},
39         {"guid", required_argument, NULL, 'g'},
40         {"active-bank", required_argument, NULL, 'a'},
41         {"previous-bank", required_argument, NULL, 'p'},
42         {"help", no_argument, NULL, 'h'},
43         {NULL, 0, NULL, 0},
44 };
45
46 static void print_usage(void)
47 {
48         fprintf(stderr, "Usage: mkfwumdata [options] <UUIDs list> <output file>\n");
49         fprintf(stderr, "Options:\n"
50                 "\t-i, --images <num>          Number of images (mandatory)\n"
51                 "\t-b, --banks  <num>          Number of banks (mandatory)\n"
52                 "\t-a, --active-bank  <num>    Active bank (default=0)\n"
53                 "\t-p, --previous-bank  <num>  Previous active bank (default=active_bank - 1)\n"
54                 "\t-g, --guid                  Use GUID instead of UUID\n"
55                 "\t-h, --help                  print a help message\n"
56                 );
57         fprintf(stderr, "  UUIDs list syntax:\n"
58                 "\t  <location uuid>,<image type uuid>,<images uuid list>\n"
59                 "\t     images uuid list syntax:\n"
60                 "\t        img_uuid_00,img_uuid_01...img_uuid_0b,\n"
61                 "\t        img_uuid_10,img_uuid_11...img_uuid_1b,\n"
62                 "\t        ...,\n"
63                 "\t        img_uuid_i0,img_uuid_i1...img_uuid_ib,\n"
64                 "\t          where 'b' and 'i' are number of banks and number\n"
65                 "\t          of images in a bank respectively.\n"
66                );
67 }
68
69 struct fwu_mdata_object {
70         size_t images;
71         size_t banks;
72         size_t size;
73         struct fwu_mdata *mdata;
74 };
75
76 static int previous_bank, active_bank;
77 static bool __use_guid;
78
79 static struct fwu_mdata_object *fwu_alloc_mdata(size_t images, size_t banks)
80 {
81         struct fwu_mdata_object *mobj;
82
83         mobj = calloc(1, sizeof(*mobj));
84         if (!mobj)
85                 return NULL;
86
87         mobj->size = sizeof(struct fwu_mdata) +
88                 (sizeof(struct fwu_image_entry) +
89                  sizeof(struct fwu_image_bank_info) * banks) * images;
90         mobj->images = images;
91         mobj->banks = banks;
92
93         mobj->mdata = calloc(1, mobj->size);
94         if (!mobj->mdata) {
95                 free(mobj);
96                 return NULL;
97         }
98
99         return mobj;
100 }
101
102 static struct fwu_image_entry *
103 fwu_get_image(struct fwu_mdata_object *mobj, size_t idx)
104 {
105         size_t offset;
106
107         offset = sizeof(struct fwu_mdata) +
108                 (sizeof(struct fwu_image_entry) +
109                  sizeof(struct fwu_image_bank_info) * mobj->banks) * idx;
110
111         return (struct fwu_image_entry *)((char *)mobj->mdata + offset);
112 }
113
114 static struct fwu_image_bank_info *
115 fwu_get_bank(struct fwu_mdata_object *mobj, size_t img_idx, size_t bnk_idx)
116 {
117         size_t offset;
118
119         offset = sizeof(struct fwu_mdata) +
120                 (sizeof(struct fwu_image_entry) +
121                  sizeof(struct fwu_image_bank_info) * mobj->banks) * img_idx +
122                 sizeof(struct fwu_image_entry) +
123                 sizeof(struct fwu_image_bank_info) * bnk_idx;
124
125         return (struct fwu_image_bank_info *)((char *)mobj->mdata + offset);
126 }
127
128 /**
129  * convert_uuid_to_guid() - convert UUID to GUID
130  * @buf:        UUID binary
131  *
132  * UUID and GUID have the same data structure, but their binary
133  * formats are different due to the endianness. See lib/uuid.c.
134  * Since uuid_parse() can handle only UUID, this function must
135  * be called to get correct data for GUID when parsing a string.
136  *
137  * The correct data will be returned in @buf.
138  */
139 static void convert_uuid_to_guid(unsigned char *buf)
140 {
141         unsigned char c;
142
143         c = buf[0];
144         buf[0] = buf[3];
145         buf[3] = c;
146         c = buf[1];
147         buf[1] = buf[2];
148         buf[2] = c;
149
150         c = buf[4];
151         buf[4] = buf[5];
152         buf[5] = c;
153
154         c = buf[6];
155         buf[6] = buf[7];
156         buf[7] = c;
157 }
158
159 static int uuid_guid_parse(char *uuidstr, unsigned char *uuid)
160 {
161         int ret;
162
163         ret = uuid_parse(uuidstr, uuid);
164         if (ret < 0)
165                 return ret;
166
167         if (__use_guid)
168                 convert_uuid_to_guid(uuid);
169
170         return ret;
171 }
172
173 static int
174 fwu_parse_fill_image_uuid(struct fwu_mdata_object *mobj,
175                           size_t idx, char *uuids)
176 {
177         struct fwu_image_entry *image = fwu_get_image(mobj, idx);
178         struct fwu_image_bank_info *bank;
179         char *p = uuids, *uuid;
180         int i;
181
182         if (!image)
183                 return -ENOENT;
184
185         /* Image location UUID */
186         uuid = strsep(&p, ",");
187         if (!uuid)
188                 return -EINVAL;
189
190         if (strcmp(uuid, "0") &&
191             uuid_guid_parse(uuid, (unsigned char *)&image->location_uuid) < 0)
192                 return -EINVAL;
193
194         /* Image type UUID */
195         uuid = strsep(&p, ",");
196         if (!uuid)
197                 return -EINVAL;
198
199         if (uuid_guid_parse(uuid, (unsigned char *)&image->image_type_uuid) < 0)
200                 return -EINVAL;
201
202         /* Fill bank image-UUID */
203         for (i = 0; i < mobj->banks; i++) {
204                 bank = fwu_get_bank(mobj, idx, i);
205                 if (!bank)
206                         return -ENOENT;
207                 bank->accepted = 1;
208                 uuid = strsep(&p, ",");
209                 if (!uuid)
210                         return -EINVAL;
211
212                 if (strcmp(uuid, "0") &&
213                     uuid_guid_parse(uuid, (unsigned char *)&bank->image_uuid) < 0)
214                         return -EINVAL;
215         }
216         return 0;
217 }
218
219 /* Caller must ensure that @uuids[] has @mobj->images entries. */
220 static int fwu_parse_fill_uuids(struct fwu_mdata_object *mobj, char *uuids[])
221 {
222         struct fwu_mdata *mdata = mobj->mdata;
223         int i, ret;
224
225         mdata->version = FWU_MDATA_VERSION;
226         mdata->active_index = active_bank;
227         mdata->previous_active_index = previous_bank;
228
229         for (i = 0; i < mobj->images; i++) {
230                 ret = fwu_parse_fill_image_uuid(mobj, i, uuids[i]);
231                 if (ret < 0)
232                         return ret;
233         }
234
235         mdata->crc32 = crc32(0, (const unsigned char *)&mdata->version,
236                              mobj->size - sizeof(uint32_t));
237
238         return 0;
239 }
240
241 static int
242 fwu_make_mdata(size_t images, size_t banks, char *uuids[], char *output)
243 {
244         struct fwu_mdata_object *mobj;
245         FILE *file;
246         int ret;
247
248         mobj = fwu_alloc_mdata(images, banks);
249         if (!mobj)
250                 return -ENOMEM;
251
252         ret = fwu_parse_fill_uuids(mobj, uuids);
253         if (ret < 0)
254                 goto done_make;
255
256         file = fopen(output, "w");
257         if (!file) {
258                 ret = -errno;
259                 goto done_make;
260         }
261
262         ret = fwrite(mobj->mdata, mobj->size, 1, file);
263         if (ret != mobj->size)
264                 ret = -errno;
265         else
266                 ret = 0;
267
268         fclose(file);
269
270 done_make:
271         free(mobj->mdata);
272         free(mobj);
273
274         return ret;
275 }
276
277 int main(int argc, char *argv[])
278 {
279         unsigned long banks = 0, images = 0;
280         int c, ret;
281
282         /* Explicitly initialize defaults */
283         active_bank = 0;
284         __use_guid = false;
285         previous_bank = INT_MAX;
286
287         do {
288                 c = getopt_long(argc, argv, opts_short, options, NULL);
289                 switch (c) {
290                 case 'h':
291                         print_usage();
292                         return 0;
293                 case 'b':
294                         banks = strtoul(optarg, NULL, 0);
295                         break;
296                 case 'i':
297                         images = strtoul(optarg, NULL, 0);
298                         break;
299                 case 'g':
300                         __use_guid = true;
301                         break;
302                 case 'p':
303                         previous_bank = strtoul(optarg, NULL, 0);
304                         break;
305                 case 'a':
306                         active_bank = strtoul(optarg, NULL, 0);
307                         break;
308                 }
309         } while (c != -1);
310
311         if (!banks || !images) {
312                 fprintf(stderr, "Error: The number of banks and images must not be 0.\n");
313                 return -EINVAL;
314         }
315
316         /* This command takes UUIDs * images and output file. */
317         if (optind + images + 1 != argc) {
318                 fprintf(stderr, "Error: UUID list or output file is not specified or too much.\n");
319                 print_usage();
320                 return -ERANGE;
321         }
322
323         if (previous_bank == INT_MAX) {
324                 /* set to the earlier bank in round-robin scheme */
325                 previous_bank = active_bank > 0 ? active_bank - 1 : banks - 1;
326         }
327
328         ret = fwu_make_mdata(images, banks, argv + optind, argv[argc - 1]);
329         if (ret < 0)
330                 fprintf(stderr, "Error: Failed to parse and write image: %s\n",
331                         strerror(-ret));
332
333         return ret;
334 }