blob: 27119a1aaa477342e16389b351e8fdab6f4f2dfb [file] [log] [blame]
dp-arm4972ec52016-05-25 16:20:20 +01001/*
Manish V Badarkhe7b425de2024-07-19 08:31:51 +01002 * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
dp-arm4972ec52016-05-25 16:20:20 +01003 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
dp-arm4972ec52016-05-25 16:20:20 +01005 */
6
Manish V Badarkhe7b425de2024-07-19 08:31:51 +01007#ifdef __linux__
Antonio Borneo16995302022-09-22 12:15:27 +02008#include <sys/mount.h>
9#endif
Manish V Badarkhe7b425de2024-07-19 08:31:51 +010010
dp-arm4972ec52016-05-25 16:20:20 +010011#include <sys/types.h>
12#include <sys/stat.h>
13
14#include <assert.h>
15#include <errno.h>
dp-arm4972ec52016-05-25 16:20:20 +010016#include <limits.h>
17#include <stdarg.h>
18#include <stdint.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
Masahiro Yamadae3a2b312017-05-08 18:29:03 +090022
dp-arm4972ec52016-05-25 16:20:20 +010023#include "fiptool.h"
dp-arm4972ec52016-05-25 16:20:20 +010024#include "tbbr_config.h"
25
26#define OPT_TOC_ENTRY 0
27#define OPT_PLAT_TOC_FLAGS 1
Masahiro Yamada4d87eb42016-12-25 13:52:22 +090028#define OPT_ALIGN 2
dp-arm4972ec52016-05-25 16:20:20 +010029
30static int info_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050031static void info_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010032static int create_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050033static void create_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010034static int update_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050035static void update_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010036static int unpack_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050037static void unpack_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010038static int remove_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050039static void remove_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010040static int version_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050041static void version_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010042static int help_cmd(int argc, char *argv[]);
43static void usage(void);
44
45/* Available subcommands. */
46static cmd_t cmds[] = {
47 { .name = "info", .handler = info_cmd, .usage = info_usage },
48 { .name = "create", .handler = create_cmd, .usage = create_usage },
49 { .name = "update", .handler = update_cmd, .usage = update_usage },
50 { .name = "unpack", .handler = unpack_cmd, .usage = unpack_usage },
51 { .name = "remove", .handler = remove_cmd, .usage = remove_usage },
52 { .name = "version", .handler = version_cmd, .usage = version_usage },
53 { .name = "help", .handler = help_cmd, .usage = NULL },
54};
55
dp-arm90d2f0e2016-11-14 15:54:32 +000056static image_desc_t *image_desc_head;
57static size_t nr_image_descs;
Roberto Vargaseace8f12018-04-26 13:36:53 +010058static const uuid_t uuid_null;
dp-arm4972ec52016-05-25 16:20:20 +010059static int verbose;
60
dp-armc1f8e772016-11-04 10:52:25 +000061static void vlog(int prio, const char *msg, va_list ap)
dp-arm4972ec52016-05-25 16:20:20 +010062{
63 char *prefix[] = { "DEBUG", "WARN", "ERROR" };
64
65 fprintf(stderr, "%s: ", prefix[prio]);
66 vfprintf(stderr, msg, ap);
67 fputc('\n', stderr);
68}
69
dp-armc1f8e772016-11-04 10:52:25 +000070static void log_dbgx(const char *msg, ...)
dp-arm4972ec52016-05-25 16:20:20 +010071{
72 va_list ap;
73
74 va_start(ap, msg);
75 vlog(LOG_DBG, msg, ap);
76 va_end(ap);
77}
78
dp-armc1f8e772016-11-04 10:52:25 +000079static void log_warnx(const char *msg, ...)
dp-arm4972ec52016-05-25 16:20:20 +010080{
81 va_list ap;
82
83 va_start(ap, msg);
84 vlog(LOG_WARN, msg, ap);
85 va_end(ap);
86}
87
dp-armc1f8e772016-11-04 10:52:25 +000088static void log_err(const char *msg, ...)
dp-arm4972ec52016-05-25 16:20:20 +010089{
90 char buf[512];
91 va_list ap;
92
93 va_start(ap, msg);
94 snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno));
95 vlog(LOG_ERR, buf, ap);
96 va_end(ap);
97 exit(1);
98}
99
dp-armc1f8e772016-11-04 10:52:25 +0000100static void log_errx(const char *msg, ...)
dp-arm4972ec52016-05-25 16:20:20 +0100101{
102 va_list ap;
103
104 va_start(ap, msg);
105 vlog(LOG_ERR, msg, ap);
106 va_end(ap);
107 exit(1);
108}
109
dp-armdb0f5e92016-11-04 10:56:25 +0000110static char *xstrdup(const char *s, const char *msg)
111{
112 char *d;
113
114 d = strdup(s);
115 if (d == NULL)
dp-arm5ba38542016-12-21 14:59:30 +0000116 log_errx("strdup: %s", msg);
dp-armdb0f5e92016-11-04 10:56:25 +0000117 return d;
118}
119
120static void *xmalloc(size_t size, const char *msg)
121{
122 void *d;
123
124 d = malloc(size);
125 if (d == NULL)
dp-arm5ba38542016-12-21 14:59:30 +0000126 log_errx("malloc: %s", msg);
dp-armdb0f5e92016-11-04 10:56:25 +0000127 return d;
128}
129
Masahiro Yamada03fdf692017-01-15 00:50:41 +0900130static void *xzalloc(size_t size, const char *msg)
131{
132 return memset(xmalloc(size, msg), 0, size);
133}
134
Masahiro Yamada23f9b9e2017-01-27 03:54:02 +0900135static void xfwrite(void *buf, size_t size, FILE *fp, const char *filename)
136{
137 if (fwrite(buf, 1, size, fp) != size)
138 log_errx("Failed to write %s", filename);
139}
140
dp-arm90d2f0e2016-11-14 15:54:32 +0000141static image_desc_t *new_image_desc(const uuid_t *uuid,
142 const char *name, const char *cmdline_name)
dp-arm4972ec52016-05-25 16:20:20 +0100143{
dp-arm90d2f0e2016-11-14 15:54:32 +0000144 image_desc_t *desc;
145
Masahiro Yamada03fdf692017-01-15 00:50:41 +0900146 desc = xzalloc(sizeof(*desc),
dp-arm90d2f0e2016-11-14 15:54:32 +0000147 "failed to allocate memory for image descriptor");
148 memcpy(&desc->uuid, uuid, sizeof(uuid_t));
149 desc->name = xstrdup(name,
150 "failed to allocate memory for image name");
151 desc->cmdline_name = xstrdup(cmdline_name,
152 "failed to allocate memory for image command line name");
153 desc->action = DO_UNSPEC;
dp-arm90d2f0e2016-11-14 15:54:32 +0000154 return desc;
dp-arm4972ec52016-05-25 16:20:20 +0100155}
156
dp-armfb732312016-12-30 09:55:48 +0000157static void set_image_desc_action(image_desc_t *desc, int action,
158 const char *arg)
159{
160 assert(desc != NULL);
161
Evan Lloyd04dc3442017-05-25 19:06:47 +0100162 if (desc->action_arg != (char *)DO_UNSPEC)
dp-armfb732312016-12-30 09:55:48 +0000163 free(desc->action_arg);
164 desc->action = action;
165 desc->action_arg = NULL;
166 if (arg != NULL)
167 desc->action_arg = xstrdup(arg,
168 "failed to allocate memory for argument");
169}
170
dp-arm90d2f0e2016-11-14 15:54:32 +0000171static void free_image_desc(image_desc_t *desc)
dp-arm4972ec52016-05-25 16:20:20 +0100172{
dp-arm90d2f0e2016-11-14 15:54:32 +0000173 free(desc->name);
174 free(desc->cmdline_name);
175 free(desc->action_arg);
Jonathan Wright242cd3c2018-05-03 15:05:09 +0100176 if (desc->image) {
177 free(desc->image->buffer);
178 free(desc->image);
179 }
dp-arm90d2f0e2016-11-14 15:54:32 +0000180 free(desc);
dp-arm4972ec52016-05-25 16:20:20 +0100181}
182
dp-arm90d2f0e2016-11-14 15:54:32 +0000183static void add_image_desc(image_desc_t *desc)
dp-arm4972ec52016-05-25 16:20:20 +0100184{
Masahiro Yamadad224b452017-01-14 23:22:02 +0900185 image_desc_t **p = &image_desc_head;
186
Masahiro Yamadad224b452017-01-14 23:22:02 +0900187 while (*p)
188 p = &(*p)->next;
189
Masahiro Yamadac2a7d9c2017-01-27 12:53:13 +0900190 assert(*p == NULL);
Masahiro Yamadad224b452017-01-14 23:22:02 +0900191 *p = desc;
dp-arm90d2f0e2016-11-14 15:54:32 +0000192 nr_image_descs++;
193}
dp-arm4972ec52016-05-25 16:20:20 +0100194
dp-arm90d2f0e2016-11-14 15:54:32 +0000195static void free_image_descs(void)
196{
197 image_desc_t *desc = image_desc_head, *tmp;
198
199 while (desc != NULL) {
200 tmp = desc->next;
201 free_image_desc(desc);
202 desc = tmp;
203 nr_image_descs--;
dp-arm4972ec52016-05-25 16:20:20 +0100204 }
dp-arm90d2f0e2016-11-14 15:54:32 +0000205 assert(nr_image_descs == 0);
dp-arm4972ec52016-05-25 16:20:20 +0100206}
207
dp-arm90d2f0e2016-11-14 15:54:32 +0000208static void fill_image_descs(void)
209{
210 toc_entry_t *toc_entry;
211
212 for (toc_entry = toc_entries;
213 toc_entry->cmdline_name != NULL;
214 toc_entry++) {
215 image_desc_t *desc;
216
217 desc = new_image_desc(&toc_entry->uuid,
218 toc_entry->name,
219 toc_entry->cmdline_name);
220 add_image_desc(desc);
221 }
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +0530222#ifdef PLAT_DEF_FIP_UUID
223 for (toc_entry = plat_def_toc_entries;
224 toc_entry->cmdline_name != NULL;
225 toc_entry++) {
226 image_desc_t *desc;
227
228 desc = new_image_desc(&toc_entry->uuid,
229 toc_entry->name,
230 toc_entry->cmdline_name);
231 add_image_desc(desc);
232 }
233#endif
dp-arm90d2f0e2016-11-14 15:54:32 +0000234}
235
dp-arm90d2f0e2016-11-14 15:54:32 +0000236static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid)
dp-arm4972ec52016-05-25 16:20:20 +0100237{
dp-arm90d2f0e2016-11-14 15:54:32 +0000238 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100239
dp-arm90d2f0e2016-11-14 15:54:32 +0000240 for (desc = image_desc_head; desc != NULL; desc = desc->next)
241 if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
242 return desc;
dp-arm4972ec52016-05-25 16:20:20 +0100243 return NULL;
244}
245
dp-arm90d2f0e2016-11-14 15:54:32 +0000246static image_desc_t *lookup_image_desc_from_opt(const char *opt)
247{
248 image_desc_t *desc;
249
250 for (desc = image_desc_head; desc != NULL; desc = desc->next)
251 if (strcmp(desc->cmdline_name, opt) == 0)
252 return desc;
253 return NULL;
254}
255
dp-arm516dfcb2016-11-03 13:59:26 +0000256static void uuid_to_str(char *s, size_t len, const uuid_t *u)
257{
258 assert(len >= (_UUID_STR_LEN + 1));
259
Roberto Vargaseace8f12018-04-26 13:36:53 +0100260 snprintf(s, len,
261 "%02X%02X%02X%02X-%02X%02X-%02X%02X-%04X-%04X%04X%04X",
262 u->time_low[0], u->time_low[1], u->time_low[2], u->time_low[3],
263 u->time_mid[0], u->time_mid[1],
264 u->time_hi_and_version[0], u->time_hi_and_version[1],
265 (u->clock_seq_hi_and_reserved << 8) | u->clock_seq_low,
266 (u->node[0] << 8) | u->node[1],
267 (u->node[2] << 8) | u->node[3],
268 (u->node[4] << 8) | u->node[5]);
dp-arm516dfcb2016-11-03 13:59:26 +0000269}
270
271static void uuid_from_str(uuid_t *u, const char *s)
272{
273 int n;
274
275 if (s == NULL)
276 log_errx("UUID cannot be NULL");
277 if (strlen(s) != _UUID_STR_LEN)
278 log_errx("Invalid UUID: %s", s);
279
280 n = sscanf(s,
Roberto Vargaseace8f12018-04-26 13:36:53 +0100281 "%2hhx%2hhx%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
282 &u->time_low[0], &u->time_low[1], &u->time_low[2], &u->time_low[3],
283 &u->time_mid[0], &u->time_mid[1],
284 &u->time_hi_and_version[0], &u->time_hi_and_version[1],
285 &u->clock_seq_hi_and_reserved, &u->clock_seq_low,
286 &u->node[0], &u->node[1],
287 &u->node[2], &u->node[3],
288 &u->node[4], &u->node[5]);
dp-arm516dfcb2016-11-03 13:59:26 +0000289 /*
Andre Przywaraf41e53c2019-01-29 09:25:14 +0000290 * Given the format specifier above, we expect 16 items to be scanned
dp-arm516dfcb2016-11-03 13:59:26 +0000291 * for a properly formatted UUID.
292 */
Andre Przywaraf41e53c2019-01-29 09:25:14 +0000293 if (n != 16)
dp-arm516dfcb2016-11-03 13:59:26 +0000294 log_errx("Invalid UUID: %s", s);
295}
296
dp-armc1f8e772016-11-04 10:52:25 +0000297static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
dp-arm4972ec52016-05-25 16:20:20 +0100298{
Evan Lloyd04dc3442017-05-25 19:06:47 +0100299 struct BLD_PLAT_STAT st;
dp-arm4972ec52016-05-25 16:20:20 +0100300 FILE *fp;
301 char *buf, *bufend;
302 fip_toc_header_t *toc_header;
303 fip_toc_entry_t *toc_entry;
dp-arm4972ec52016-05-25 16:20:20 +0100304 int terminated = 0;
Antonio Borneo16995302022-09-22 12:15:27 +0200305 size_t st_size;
dp-arm4972ec52016-05-25 16:20:20 +0100306
Evan Lloydb1939392017-01-13 14:13:09 +0000307 fp = fopen(filename, "rb");
dp-arm4972ec52016-05-25 16:20:20 +0100308 if (fp == NULL)
309 log_err("fopen %s", filename);
310
311 if (fstat(fileno(fp), &st) == -1)
312 log_err("fstat %s", filename);
313
Antonio Borneo16995302022-09-22 12:15:27 +0200314 st_size = st.st_size;
315
316#ifdef BLKGETSIZE64
317 if ((st.st_mode & S_IFBLK) != 0)
318 if (ioctl(fileno(fp), BLKGETSIZE64, &st_size) == -1)
319 log_err("ioctl %s", filename);
320#endif
321
322 buf = xmalloc(st_size, "failed to load file into memory");
323 if (fread(buf, 1, st_size, fp) != st_size)
dp-arm4972ec52016-05-25 16:20:20 +0100324 log_errx("Failed to read %s", filename);
Antonio Borneo16995302022-09-22 12:15:27 +0200325 bufend = buf + st_size;
dp-arm4972ec52016-05-25 16:20:20 +0100326 fclose(fp);
327
Antonio Borneo16995302022-09-22 12:15:27 +0200328 if (st_size < sizeof(fip_toc_header_t))
dp-arm4972ec52016-05-25 16:20:20 +0100329 log_errx("FIP %s is truncated", filename);
330
331 toc_header = (fip_toc_header_t *)buf;
332 toc_entry = (fip_toc_entry_t *)(toc_header + 1);
333
334 if (toc_header->name != TOC_HEADER_NAME)
335 log_errx("%s is not a FIP file", filename);
336
337 /* Return the ToC header if the caller wants it. */
338 if (toc_header_out != NULL)
339 *toc_header_out = *toc_header;
340
341 /* Walk through each ToC entry in the file. */
342 while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) {
dp-arm516dfcb2016-11-03 13:59:26 +0000343 image_t *image;
344 image_desc_t *desc;
345
dp-arm4972ec52016-05-25 16:20:20 +0100346 /* Found the ToC terminator, we are done. */
347 if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) {
348 terminated = 1;
349 break;
350 }
351
352 /*
353 * Build a new image out of the ToC entry and add it to the
354 * table of images.
355 */
Masahiro Yamadad224b452017-01-14 23:22:02 +0900356 image = xzalloc(sizeof(*image),
dp-armdb0f5e92016-11-04 10:56:25 +0000357 "failed to allocate memory for image");
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900358 image->toc_e = *toc_entry;
dp-armdb0f5e92016-11-04 10:56:25 +0000359 image->buffer = xmalloc(toc_entry->size,
360 "failed to allocate image buffer, is FIP file corrupted?");
dp-arm4972ec52016-05-25 16:20:20 +0100361 /* Overflow checks before memory copy. */
362 if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address)
Antonio Borneo16995302022-09-22 12:15:27 +0200363 log_errx("FIP %s is corrupted: entry size exceeds 64 bit address space",
364 filename);
365 if (toc_entry->size + toc_entry->offset_address > st_size)
366 log_errx("FIP %s is corrupted: entry size exceeds FIP file size",
367 filename);
dp-arm4972ec52016-05-25 16:20:20 +0100368
369 memcpy(image->buffer, buf + toc_entry->offset_address,
370 toc_entry->size);
dp-arm4972ec52016-05-25 16:20:20 +0100371
dp-arm516dfcb2016-11-03 13:59:26 +0000372 /* If this is an unknown image, create a descriptor for it. */
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900373 desc = lookup_image_desc_from_uuid(&toc_entry->uuid);
dp-arm516dfcb2016-11-03 13:59:26 +0000374 if (desc == NULL) {
375 char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
376
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900377 uuid_to_str(name, sizeof(name), &toc_entry->uuid);
dp-arm516dfcb2016-11-03 13:59:26 +0000378 snprintf(filename, sizeof(filename), "%s%s",
379 name, ".bin");
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900380 desc = new_image_desc(&toc_entry->uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000381 desc->action = DO_UNPACK;
382 desc->action_arg = xstrdup(filename,
383 "failed to allocate memory for blob filename");
384 add_image_desc(desc);
385 }
386
dp-armafa1efa2017-02-14 15:22:13 +0000387 assert(desc->image == NULL);
388 desc->image = image;
dp-arm4972ec52016-05-25 16:20:20 +0100389
390 toc_entry++;
391 }
392
393 if (terminated == 0)
394 log_errx("FIP %s does not have a ToC terminator entry",
395 filename);
396 free(buf);
397 return 0;
398}
399
dp-armc1f8e772016-11-04 10:52:25 +0000400static image_t *read_image_from_file(const uuid_t *uuid, const char *filename)
dp-arm4972ec52016-05-25 16:20:20 +0100401{
Evan Lloyd04dc3442017-05-25 19:06:47 +0100402 struct BLD_PLAT_STAT st;
dp-arm4972ec52016-05-25 16:20:20 +0100403 image_t *image;
404 FILE *fp;
405
dp-arm715ef422016-08-30 14:18:58 +0100406 assert(uuid != NULL);
Evan Lloyd04dc3442017-05-25 19:06:47 +0100407 assert(filename != NULL);
dp-arm715ef422016-08-30 14:18:58 +0100408
Evan Lloydb1939392017-01-13 14:13:09 +0000409 fp = fopen(filename, "rb");
dp-arm4972ec52016-05-25 16:20:20 +0100410 if (fp == NULL)
411 log_err("fopen %s", filename);
412
413 if (fstat(fileno(fp), &st) == -1)
414 log_errx("fstat %s", filename);
415
Masahiro Yamadad224b452017-01-14 23:22:02 +0900416 image = xzalloc(sizeof(*image), "failed to allocate memory for image");
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900417 image->toc_e.uuid = *uuid;
dp-armdb0f5e92016-11-04 10:56:25 +0000418 image->buffer = xmalloc(st.st_size, "failed to allocate image buffer");
dp-arm4972ec52016-05-25 16:20:20 +0100419 if (fread(image->buffer, 1, st.st_size, fp) != st.st_size)
420 log_errx("Failed to read %s", filename);
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900421 image->toc_e.size = st.st_size;
dp-arm4972ec52016-05-25 16:20:20 +0100422
423 fclose(fp);
424 return image;
425}
426
dp-armc1f8e772016-11-04 10:52:25 +0000427static int write_image_to_file(const image_t *image, const char *filename)
dp-arm4972ec52016-05-25 16:20:20 +0100428{
429 FILE *fp;
430
Evan Lloydb1939392017-01-13 14:13:09 +0000431 fp = fopen(filename, "wb");
dp-arm4972ec52016-05-25 16:20:20 +0100432 if (fp == NULL)
433 log_err("fopen");
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900434 xfwrite(image->buffer, image->toc_e.size, fp, filename);
dp-arm4972ec52016-05-25 16:20:20 +0100435 fclose(fp);
436 return 0;
437}
438
dp-arm90d2f0e2016-11-14 15:54:32 +0000439static struct option *add_opt(struct option *opts, size_t *nr_opts,
440 const char *name, int has_arg, int val)
dp-arm4972ec52016-05-25 16:20:20 +0100441{
dp-arm90d2f0e2016-11-14 15:54:32 +0000442 opts = realloc(opts, (*nr_opts + 1) * sizeof(*opts));
443 if (opts == NULL)
444 log_err("realloc");
445 opts[*nr_opts].name = name;
446 opts[*nr_opts].has_arg = has_arg;
447 opts[*nr_opts].flag = NULL;
448 opts[*nr_opts].val = val;
449 ++*nr_opts;
450 return opts;
dp-arm4972ec52016-05-25 16:20:20 +0100451}
452
dp-arm90d2f0e2016-11-14 15:54:32 +0000453static struct option *fill_common_opts(struct option *opts, size_t *nr_opts,
454 int has_arg)
dp-arm4972ec52016-05-25 16:20:20 +0100455{
dp-arm90d2f0e2016-11-14 15:54:32 +0000456 image_desc_t *desc;
457
458 for (desc = image_desc_head; desc != NULL; desc = desc->next)
459 opts = add_opt(opts, nr_opts, desc->cmdline_name, has_arg,
460 OPT_TOC_ENTRY);
461 return opts;
dp-arm4972ec52016-05-25 16:20:20 +0100462}
463
Olivier Deprez9b9a5dc2023-08-31 11:46:54 +0200464#if !STATIC
dp-arm90d2f0e2016-11-14 15:54:32 +0000465static void md_print(const unsigned char *md, size_t len)
dp-arm12e893b2016-08-24 13:21:08 +0100466{
467 size_t i;
468
469 for (i = 0; i < len; i++)
470 printf("%02x", md[i]);
471}
Olivier Deprez9b9a5dc2023-08-31 11:46:54 +0200472#endif
dp-arm12e893b2016-08-24 13:21:08 +0100473
dp-arm4972ec52016-05-25 16:20:20 +0100474static int info_cmd(int argc, char *argv[])
475{
dp-armafa1efa2017-02-14 15:22:13 +0000476 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100477 fip_toc_header_t toc_header;
dp-arm4972ec52016-05-25 16:20:20 +0100478
479 if (argc != 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500480 info_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100481 argc--, argv++;
482
483 parse_fip(argv[0], &toc_header);
484
485 if (verbose) {
486 log_dbgx("toc_header[name]: 0x%llX",
487 (unsigned long long)toc_header.name);
488 log_dbgx("toc_header[serial_number]: 0x%llX",
489 (unsigned long long)toc_header.serial_number);
490 log_dbgx("toc_header[flags]: 0x%llX",
491 (unsigned long long)toc_header.flags);
492 }
493
dp-armafa1efa2017-02-14 15:22:13 +0000494 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
495 image_t *image = desc->image;
dp-arm715ef422016-08-30 14:18:58 +0100496
dp-armafa1efa2017-02-14 15:22:13 +0000497 if (image == NULL)
498 continue;
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900499 printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"--%s\"",
500 desc->name,
501 (unsigned long long)image->toc_e.offset_address,
502 (unsigned long long)image->toc_e.size,
Masahiro Yamadaeee39312017-01-15 23:20:00 +0900503 desc->cmdline_name);
Olivier Deprez9b9a5dc2023-08-31 11:46:54 +0200504
505 /*
506 * Omit this informative code portion for:
507 * Visual Studio missing SHA256.
508 * Statically linked builds.
509 */
510#if !defined(_MSC_VER) && !STATIC
dp-arm12e893b2016-08-24 13:21:08 +0100511 if (verbose) {
512 unsigned char md[SHA256_DIGEST_LENGTH];
513
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900514 SHA256(image->buffer, image->toc_e.size, md);
dp-arm12e893b2016-08-24 13:21:08 +0100515 printf(", sha256=");
516 md_print(md, sizeof(md));
517 }
Evan Lloyd04dc3442017-05-25 19:06:47 +0100518#endif
dp-arm12e893b2016-08-24 13:21:08 +0100519 putchar('\n');
dp-arm4972ec52016-05-25 16:20:20 +0100520 }
521
dp-arm4972ec52016-05-25 16:20:20 +0100522 return 0;
523}
524
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500525static void info_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +0100526{
527 printf("fiptool info FIP_FILENAME\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500528 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +0100529}
530
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900531static int pack_images(const char *filename, uint64_t toc_flags, unsigned long align)
dp-arm4972ec52016-05-25 16:20:20 +0100532{
533 FILE *fp;
dp-armafa1efa2017-02-14 15:22:13 +0000534 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100535 fip_toc_header_t *toc_header;
536 fip_toc_entry_t *toc_entry;
537 char *buf;
Roberto Vargas81935762017-12-19 11:56:57 +0000538 uint64_t entry_offset, buf_size, payload_size = 0, pad_size;
dp-armafa1efa2017-02-14 15:22:13 +0000539 size_t nr_images = 0;
540
541 for (desc = image_desc_head; desc != NULL; desc = desc->next)
542 if (desc->image != NULL)
543 nr_images++;
dp-arm4972ec52016-05-25 16:20:20 +0100544
545 buf_size = sizeof(fip_toc_header_t) +
546 sizeof(fip_toc_entry_t) * (nr_images + 1);
547 buf = calloc(1, buf_size);
548 if (buf == NULL)
549 log_err("calloc");
550
551 /* Build up header and ToC entries from the image table. */
552 toc_header = (fip_toc_header_t *)buf;
553 toc_header->name = TOC_HEADER_NAME;
554 toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
555 toc_header->flags = toc_flags;
556
557 toc_entry = (fip_toc_entry_t *)(toc_header + 1);
558
559 entry_offset = buf_size;
dp-armafa1efa2017-02-14 15:22:13 +0000560 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
561 image_t *image = desc->image;
562
Manish V Badarkhe0624d732021-12-18 11:26:25 +0000563 if (image == NULL || (image->toc_e.size == 0ULL))
dp-armafa1efa2017-02-14 15:22:13 +0000564 continue;
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900565 payload_size += image->toc_e.size;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900566 entry_offset = (entry_offset + align - 1) & ~(align - 1);
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900567 image->toc_e.offset_address = entry_offset;
568 *toc_entry++ = image->toc_e;
569 entry_offset += image->toc_e.size;
dp-arm4972ec52016-05-25 16:20:20 +0100570 }
571
Roberto Vargas81935762017-12-19 11:56:57 +0000572 /*
573 * Append a null uuid entry to mark the end of ToC entries.
574 * NOTE the offset address for the last toc_entry must match the fip
575 * size.
576 */
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900577 memset(toc_entry, 0, sizeof(*toc_entry));
Roberto Vargas81935762017-12-19 11:56:57 +0000578 toc_entry->offset_address = (entry_offset + align - 1) & ~(align - 1);
dp-arm4972ec52016-05-25 16:20:20 +0100579
580 /* Generate the FIP file. */
Evan Lloydb1939392017-01-13 14:13:09 +0000581 fp = fopen(filename, "wb");
dp-arm4972ec52016-05-25 16:20:20 +0100582 if (fp == NULL)
583 log_err("fopen %s", filename);
584
585 if (verbose)
586 log_dbgx("Metadata size: %zu bytes", buf_size);
587
Masahiro Yamada23f9b9e2017-01-27 03:54:02 +0900588 xfwrite(buf, buf_size, fp, filename);
dp-arm4972ec52016-05-25 16:20:20 +0100589
590 if (verbose)
591 log_dbgx("Payload size: %zu bytes", payload_size);
592
dp-armafa1efa2017-02-14 15:22:13 +0000593 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
594 image_t *image = desc->image;
595
596 if (image == NULL)
597 continue;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900598 if (fseek(fp, image->toc_e.offset_address, SEEK_SET))
599 log_errx("Failed to set file position");
600
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900601 xfwrite(image->buffer, image->toc_e.size, fp, filename);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900602 }
dp-arm4972ec52016-05-25 16:20:20 +0100603
Roberto Vargas81935762017-12-19 11:56:57 +0000604 if (fseek(fp, entry_offset, SEEK_SET))
605 log_errx("Failed to set file position");
606
607 pad_size = toc_entry->offset_address - entry_offset;
608 while (pad_size--)
609 fputc(0x0, fp);
610
Andreas Färber860b5dc2018-01-27 16:46:59 +0100611 free(buf);
dp-arm4972ec52016-05-25 16:20:20 +0100612 fclose(fp);
613 return 0;
614}
615
616/*
617 * This function is shared between the create and update subcommands.
618 * The difference between the two subcommands is that when the FIP file
619 * is created, the parsing of an existing FIP is skipped. This results
620 * in update_fip() creating the new FIP file from scratch because the
621 * internal image table is not populated.
622 */
623static void update_fip(void)
624{
dp-arm90d2f0e2016-11-14 15:54:32 +0000625 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100626
627 /* Add or replace images in the FIP file. */
dp-arm90d2f0e2016-11-14 15:54:32 +0000628 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
dp-armafa1efa2017-02-14 15:22:13 +0000629 image_t *image;
dp-arm516dfcb2016-11-03 13:59:26 +0000630
dp-arm90d2f0e2016-11-14 15:54:32 +0000631 if (desc->action != DO_PACK)
dp-arm4972ec52016-05-25 16:20:20 +0100632 continue;
633
dp-armafa1efa2017-02-14 15:22:13 +0000634 image = read_image_from_file(&desc->uuid,
dp-arm90d2f0e2016-11-14 15:54:32 +0000635 desc->action_arg);
dp-armafa1efa2017-02-14 15:22:13 +0000636 if (desc->image != NULL) {
dp-arm90d2f0e2016-11-14 15:54:32 +0000637 if (verbose) {
dp-arm516dfcb2016-11-03 13:59:26 +0000638 log_dbgx("Replacing %s with %s",
dp-arm90d2f0e2016-11-14 15:54:32 +0000639 desc->cmdline_name,
640 desc->action_arg);
641 }
dp-armafa1efa2017-02-14 15:22:13 +0000642 free(desc->image);
643 desc->image = image;
dp-arm4972ec52016-05-25 16:20:20 +0100644 } else {
645 if (verbose)
646 log_dbgx("Adding image %s",
dp-arm90d2f0e2016-11-14 15:54:32 +0000647 desc->action_arg);
dp-armafa1efa2017-02-14 15:22:13 +0000648 desc->image = image;
dp-arm4972ec52016-05-25 16:20:20 +0100649 }
dp-arm4972ec52016-05-25 16:20:20 +0100650 }
651}
652
dp-arm90d2f0e2016-11-14 15:54:32 +0000653static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags)
dp-arm4972ec52016-05-25 16:20:20 +0100654{
655 unsigned long long flags;
656 char *endptr;
657
658 errno = 0;
659 flags = strtoull(arg, &endptr, 16);
660 if (*endptr != '\0' || flags > UINT16_MAX || errno != 0)
661 log_errx("Invalid platform ToC flags: %s", arg);
662 /* Platform ToC flags is a 16-bit field occupying bits [32-47]. */
663 *toc_flags |= flags << 32;
664}
665
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900666static int is_power_of_2(unsigned long x)
667{
668 return x && !(x & (x - 1));
669}
670
671static unsigned long get_image_align(char *arg)
672{
673 char *endptr;
674 unsigned long align;
675
676 errno = 0;
Andreas Färber242a7b72017-04-21 19:39:10 +0200677 align = strtoul(arg, &endptr, 0);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900678 if (*endptr != '\0' || !is_power_of_2(align) || errno != 0)
679 log_errx("Invalid alignment: %s", arg);
680
681 return align;
682}
683
dp-arm516dfcb2016-11-03 13:59:26 +0000684static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len)
685{
686 char *p;
687
688 for (p = strtok(arg, ","); p != NULL; p = strtok(NULL, ",")) {
689 if (strncmp(p, "uuid=", strlen("uuid=")) == 0) {
690 p += strlen("uuid=");
691 uuid_from_str(uuid, p);
692 } else if (strncmp(p, "file=", strlen("file=")) == 0) {
693 p += strlen("file=");
694 snprintf(filename, len, "%s", p);
695 }
696 }
697}
698
dp-arm4972ec52016-05-25 16:20:20 +0100699static int create_cmd(int argc, char *argv[])
700{
dp-arm90d2f0e2016-11-14 15:54:32 +0000701 struct option *opts = NULL;
702 size_t nr_opts = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100703 unsigned long long toc_flags = 0;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900704 unsigned long align = 1;
dp-arm4972ec52016-05-25 16:20:20 +0100705
706 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500707 create_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100708
dp-arm90d2f0e2016-11-14 15:54:32 +0000709 opts = fill_common_opts(opts, &nr_opts, required_argument);
710 opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
dp-arm4972ec52016-05-25 16:20:20 +0100711 OPT_PLAT_TOC_FLAGS);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900712 opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
dp-arm516dfcb2016-11-03 13:59:26 +0000713 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +0000714 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +0100715
716 while (1) {
dp-armfe92b892016-11-07 11:13:54 +0000717 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100718
dp-arm516dfcb2016-11-03 13:59:26 +0000719 c = getopt_long(argc, argv, "b:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +0100720 if (c == -1)
721 break;
722
723 switch (c) {
724 case OPT_TOC_ENTRY: {
dp-arm90d2f0e2016-11-14 15:54:32 +0000725 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100726
dp-arm90d2f0e2016-11-14 15:54:32 +0000727 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +0000728 set_image_desc_action(desc, DO_PACK, optarg);
dp-arm4972ec52016-05-25 16:20:20 +0100729 break;
730 }
731 case OPT_PLAT_TOC_FLAGS:
732 parse_plat_toc_flags(optarg, &toc_flags);
733 break;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900734 case OPT_ALIGN:
735 align = get_image_align(optarg);
736 break;
dp-arm516dfcb2016-11-03 13:59:26 +0000737 case 'b': {
738 char name[_UUID_STR_LEN + 1];
739 char filename[PATH_MAX] = { 0 };
Roberto Vargaseace8f12018-04-26 13:36:53 +0100740 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +0000741 image_desc_t *desc;
742
743 parse_blob_opt(optarg, &uuid,
744 filename, sizeof(filename));
745
746 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
747 filename[0] == '\0')
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500748 create_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +0000749
750 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +0000751 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +0000752 uuid_to_str(name, sizeof(name), &uuid);
753 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000754 add_image_desc(desc);
755 }
dp-armfb732312016-12-30 09:55:48 +0000756 set_image_desc_action(desc, DO_PACK, filename);
dp-arm516dfcb2016-11-03 13:59:26 +0000757 break;
758 }
dp-arm4972ec52016-05-25 16:20:20 +0100759 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500760 create_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100761 }
762 }
763 argc -= optind;
764 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +0000765 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +0100766
767 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500768 create_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +0100769
770 update_fip();
771
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900772 pack_images(argv[0], toc_flags, align);
dp-arm4972ec52016-05-25 16:20:20 +0100773 return 0;
774}
775
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500776static void create_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +0100777{
778 toc_entry_t *toc_entry = toc_entries;
779
Masahiro Yamada7abd0a22017-01-14 11:04:36 +0900780 printf("fiptool create [opts] FIP_FILENAME\n");
781 printf("\n");
782 printf("Options:\n");
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900783 printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +0900784 printf(" --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n");
785 printf(" --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +0900786 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +0100787 printf("Specific images are packed with the following options:\n");
788 for (; toc_entry->cmdline_name != NULL; toc_entry++)
789 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
790 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +0530791#ifdef PLAT_DEF_FIP_UUID
792 toc_entry = plat_def_toc_entries;
793 for (; toc_entry->cmdline_name != NULL; toc_entry++)
794 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
795 toc_entry->name);
796#endif
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500797 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +0100798}
799
800static int update_cmd(int argc, char *argv[])
801{
dp-arm90d2f0e2016-11-14 15:54:32 +0000802 struct option *opts = NULL;
803 size_t nr_opts = 0;
dp-arm516dfcb2016-11-03 13:59:26 +0000804 char outfile[PATH_MAX] = { 0 };
dp-arm4972ec52016-05-25 16:20:20 +0100805 fip_toc_header_t toc_header = { 0 };
806 unsigned long long toc_flags = 0;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900807 unsigned long align = 1;
dp-arm4972ec52016-05-25 16:20:20 +0100808 int pflag = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100809
810 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500811 update_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100812
dp-arm90d2f0e2016-11-14 15:54:32 +0000813 opts = fill_common_opts(opts, &nr_opts, required_argument);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900814 opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
dp-arm516dfcb2016-11-03 13:59:26 +0000815 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +0000816 opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
817 opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
dp-arm4972ec52016-05-25 16:20:20 +0100818 OPT_PLAT_TOC_FLAGS);
dp-arm90d2f0e2016-11-14 15:54:32 +0000819 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +0100820
821 while (1) {
dp-armfe92b892016-11-07 11:13:54 +0000822 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100823
dp-arm516dfcb2016-11-03 13:59:26 +0000824 c = getopt_long(argc, argv, "b:o:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +0100825 if (c == -1)
826 break;
827
828 switch (c) {
829 case OPT_TOC_ENTRY: {
dp-arm90d2f0e2016-11-14 15:54:32 +0000830 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100831
dp-arm90d2f0e2016-11-14 15:54:32 +0000832 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +0000833 set_image_desc_action(desc, DO_PACK, optarg);
dp-arm4972ec52016-05-25 16:20:20 +0100834 break;
835 }
dp-arm90d2f0e2016-11-14 15:54:32 +0000836 case OPT_PLAT_TOC_FLAGS:
dp-arm4972ec52016-05-25 16:20:20 +0100837 parse_plat_toc_flags(optarg, &toc_flags);
838 pflag = 1;
839 break;
dp-arm516dfcb2016-11-03 13:59:26 +0000840 case 'b': {
841 char name[_UUID_STR_LEN + 1];
842 char filename[PATH_MAX] = { 0 };
Roberto Vargaseace8f12018-04-26 13:36:53 +0100843 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +0000844 image_desc_t *desc;
845
846 parse_blob_opt(optarg, &uuid,
847 filename, sizeof(filename));
848
849 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
850 filename[0] == '\0')
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500851 update_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +0000852
853 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +0000854 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +0000855 uuid_to_str(name, sizeof(name), &uuid);
856 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000857 add_image_desc(desc);
858 }
dp-armfb732312016-12-30 09:55:48 +0000859 set_image_desc_action(desc, DO_PACK, filename);
dp-arm516dfcb2016-11-03 13:59:26 +0000860 break;
861 }
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900862 case OPT_ALIGN:
863 align = get_image_align(optarg);
864 break;
dp-arm4972ec52016-05-25 16:20:20 +0100865 case 'o':
866 snprintf(outfile, sizeof(outfile), "%s", optarg);
867 break;
868 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500869 update_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100870 }
871 }
872 argc -= optind;
873 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +0000874 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +0100875
876 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500877 update_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +0100878
879 if (outfile[0] == '\0')
880 snprintf(outfile, sizeof(outfile), "%s", argv[0]);
881
Masahiro Yamadaebb6e372016-12-25 12:41:41 +0900882 if (access(argv[0], F_OK) == 0)
dp-arm4972ec52016-05-25 16:20:20 +0100883 parse_fip(argv[0], &toc_header);
884
885 if (pflag)
886 toc_header.flags &= ~(0xffffULL << 32);
887 toc_flags = (toc_header.flags |= toc_flags);
888
889 update_fip();
890
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900891 pack_images(outfile, toc_flags, align);
dp-arm4972ec52016-05-25 16:20:20 +0100892 return 0;
893}
894
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500895static void update_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +0100896{
897 toc_entry_t *toc_entry = toc_entries;
898
Masahiro Yamada7abd0a22017-01-14 11:04:36 +0900899 printf("fiptool update [opts] FIP_FILENAME\n");
900 printf("\n");
901 printf("Options:\n");
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900902 printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +0900903 printf(" --blob uuid=...,file=...\tAdd or update an image with the given UUID pointed to by file.\n");
dp-arm4972ec52016-05-25 16:20:20 +0100904 printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +0900905 printf(" --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +0900906 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +0100907 printf("Specific images are packed with the following options:\n");
908 for (; toc_entry->cmdline_name != NULL; toc_entry++)
909 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
910 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +0530911#ifdef PLAT_DEF_FIP_UUID
912 toc_entry = plat_def_toc_entries;
913 for (; toc_entry->cmdline_name != NULL; toc_entry++)
914 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
915 toc_entry->name);
916#endif
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500917 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +0100918}
919
920static int unpack_cmd(int argc, char *argv[])
921{
dp-arm90d2f0e2016-11-14 15:54:32 +0000922 struct option *opts = NULL;
923 size_t nr_opts = 0;
dp-arm516dfcb2016-11-03 13:59:26 +0000924 char outdir[PATH_MAX] = { 0 };
dp-arm90d2f0e2016-11-14 15:54:32 +0000925 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100926 int fflag = 0;
927 int unpack_all = 1;
dp-arm4972ec52016-05-25 16:20:20 +0100928
929 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500930 unpack_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100931
dp-arm90d2f0e2016-11-14 15:54:32 +0000932 opts = fill_common_opts(opts, &nr_opts, required_argument);
dp-arm516dfcb2016-11-03 13:59:26 +0000933 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +0000934 opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
935 opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
936 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +0100937
938 while (1) {
dp-armfe92b892016-11-07 11:13:54 +0000939 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100940
dp-arm516dfcb2016-11-03 13:59:26 +0000941 c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +0100942 if (c == -1)
943 break;
944
945 switch (c) {
dp-arm90d2f0e2016-11-14 15:54:32 +0000946 case OPT_TOC_ENTRY: {
947 image_desc_t *desc;
948
949 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +0000950 set_image_desc_action(desc, DO_UNPACK, optarg);
dp-arm90d2f0e2016-11-14 15:54:32 +0000951 unpack_all = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100952 break;
dp-arm90d2f0e2016-11-14 15:54:32 +0000953 }
dp-arm516dfcb2016-11-03 13:59:26 +0000954 case 'b': {
955 char name[_UUID_STR_LEN + 1];
956 char filename[PATH_MAX] = { 0 };
Roberto Vargaseace8f12018-04-26 13:36:53 +0100957 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +0000958 image_desc_t *desc;
959
960 parse_blob_opt(optarg, &uuid,
961 filename, sizeof(filename));
962
963 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
964 filename[0] == '\0')
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500965 unpack_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +0000966
967 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +0000968 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +0000969 uuid_to_str(name, sizeof(name), &uuid);
970 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000971 add_image_desc(desc);
972 }
dp-armfb732312016-12-30 09:55:48 +0000973 set_image_desc_action(desc, DO_UNPACK, filename);
dp-arm516dfcb2016-11-03 13:59:26 +0000974 unpack_all = 0;
975 break;
976 }
dp-arm4972ec52016-05-25 16:20:20 +0100977 case 'f':
978 fflag = 1;
979 break;
980 case 'o':
981 snprintf(outdir, sizeof(outdir), "%s", optarg);
982 break;
983 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500984 unpack_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100985 }
986 }
987 argc -= optind;
988 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +0000989 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +0100990
991 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500992 unpack_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +0100993
994 parse_fip(argv[0], NULL);
995
996 if (outdir[0] != '\0')
997 if (chdir(outdir) == -1)
998 log_err("chdir %s", outdir);
999
dp-arm4972ec52016-05-25 16:20:20 +01001000 /* Unpack all specified images. */
dp-arm90d2f0e2016-11-14 15:54:32 +00001001 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
dp-arm516dfcb2016-11-03 13:59:26 +00001002 char file[PATH_MAX];
dp-armafa1efa2017-02-14 15:22:13 +00001003 image_t *image = desc->image;
dp-arm715ef422016-08-30 14:18:58 +01001004
dp-arm90d2f0e2016-11-14 15:54:32 +00001005 if (!unpack_all && desc->action != DO_UNPACK)
dp-arm4972ec52016-05-25 16:20:20 +01001006 continue;
1007
1008 /* Build filename. */
dp-arm90d2f0e2016-11-14 15:54:32 +00001009 if (desc->action_arg == NULL)
dp-arm4972ec52016-05-25 16:20:20 +01001010 snprintf(file, sizeof(file), "%s.bin",
dp-arm90d2f0e2016-11-14 15:54:32 +00001011 desc->cmdline_name);
dp-arm4972ec52016-05-25 16:20:20 +01001012 else
1013 snprintf(file, sizeof(file), "%s",
dp-arm90d2f0e2016-11-14 15:54:32 +00001014 desc->action_arg);
dp-arm4972ec52016-05-25 16:20:20 +01001015
dp-arm715ef422016-08-30 14:18:58 +01001016 if (image == NULL) {
1017 if (!unpack_all)
dp-arm516dfcb2016-11-03 13:59:26 +00001018 log_warnx("%s does not exist in %s",
dp-arm715ef422016-08-30 14:18:58 +01001019 file, argv[0]);
dp-arm4972ec52016-05-25 16:20:20 +01001020 continue;
1021 }
1022
1023 if (access(file, F_OK) != 0 || fflag) {
1024 if (verbose)
1025 log_dbgx("Unpacking %s", file);
dp-arm715ef422016-08-30 14:18:58 +01001026 write_image_to_file(image, file);
dp-arm4972ec52016-05-25 16:20:20 +01001027 } else {
1028 log_warnx("File %s already exists, use --force to overwrite it",
1029 file);
1030 }
dp-arm4972ec52016-05-25 16:20:20 +01001031 }
1032
dp-arm4972ec52016-05-25 16:20:20 +01001033 return 0;
1034}
1035
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001036static void unpack_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +01001037{
1038 toc_entry_t *toc_entry = toc_entries;
1039
Masahiro Yamada7abd0a22017-01-14 11:04:36 +09001040 printf("fiptool unpack [opts] FIP_FILENAME\n");
1041 printf("\n");
1042 printf("Options:\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +09001043 printf(" --blob uuid=...,file=...\tUnpack an image with the given UUID to file.\n");
1044 printf(" --force\t\t\tIf the output file already exists, use --force to overwrite it.\n");
dp-arm516dfcb2016-11-03 13:59:26 +00001045 printf(" --out path\t\t\tSet the output directory path.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +09001046 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001047 printf("Specific images are unpacked with the following options:\n");
1048 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1049 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
1050 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +05301051#ifdef PLAT_DEF_FIP_UUID
1052 toc_entry = plat_def_toc_entries;
1053 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1054 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
1055 toc_entry->name);
1056#endif
Masahiro Yamada1b900152017-02-02 16:34:14 +09001057 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001058 printf("If no options are provided, all images will be unpacked.\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001059 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +01001060}
1061
1062static int remove_cmd(int argc, char *argv[])
1063{
dp-arm90d2f0e2016-11-14 15:54:32 +00001064 struct option *opts = NULL;
1065 size_t nr_opts = 0;
dp-arm516dfcb2016-11-03 13:59:26 +00001066 char outfile[PATH_MAX] = { 0 };
dp-arm4972ec52016-05-25 16:20:20 +01001067 fip_toc_header_t toc_header;
dp-arm90d2f0e2016-11-14 15:54:32 +00001068 image_desc_t *desc;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001069 unsigned long align = 1;
dp-arm4972ec52016-05-25 16:20:20 +01001070 int fflag = 0;
dp-arm4972ec52016-05-25 16:20:20 +01001071
1072 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001073 remove_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +01001074
dp-arm90d2f0e2016-11-14 15:54:32 +00001075 opts = fill_common_opts(opts, &nr_opts, no_argument);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001076 opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
dp-arm516dfcb2016-11-03 13:59:26 +00001077 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +00001078 opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
1079 opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
1080 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +01001081
1082 while (1) {
dp-armfe92b892016-11-07 11:13:54 +00001083 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +01001084
dp-arm516dfcb2016-11-03 13:59:26 +00001085 c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +01001086 if (c == -1)
1087 break;
1088
1089 switch (c) {
dp-arm90d2f0e2016-11-14 15:54:32 +00001090 case OPT_TOC_ENTRY: {
1091 image_desc_t *desc;
1092
1093 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +00001094 set_image_desc_action(desc, DO_REMOVE, NULL);
dp-arm4972ec52016-05-25 16:20:20 +01001095 break;
dp-arm90d2f0e2016-11-14 15:54:32 +00001096 }
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001097 case OPT_ALIGN:
1098 align = get_image_align(optarg);
1099 break;
dp-arm516dfcb2016-11-03 13:59:26 +00001100 case 'b': {
1101 char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
Roberto Vargaseace8f12018-04-26 13:36:53 +01001102 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +00001103 image_desc_t *desc;
1104
1105 parse_blob_opt(optarg, &uuid,
1106 filename, sizeof(filename));
1107
1108 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001109 remove_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +00001110
1111 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +00001112 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +00001113 uuid_to_str(name, sizeof(name), &uuid);
1114 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +00001115 add_image_desc(desc);
1116 }
dp-armfb732312016-12-30 09:55:48 +00001117 set_image_desc_action(desc, DO_REMOVE, NULL);
dp-arm516dfcb2016-11-03 13:59:26 +00001118 break;
1119 }
dp-arm4972ec52016-05-25 16:20:20 +01001120 case 'f':
1121 fflag = 1;
1122 break;
1123 case 'o':
1124 snprintf(outfile, sizeof(outfile), "%s", optarg);
1125 break;
1126 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001127 remove_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +01001128 }
1129 }
1130 argc -= optind;
1131 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +00001132 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +01001133
1134 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001135 remove_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +01001136
1137 if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag)
1138 log_errx("File %s already exists, use --force to overwrite it",
1139 outfile);
1140
1141 if (outfile[0] == '\0')
1142 snprintf(outfile, sizeof(outfile), "%s", argv[0]);
1143
1144 parse_fip(argv[0], &toc_header);
1145
dp-arm90d2f0e2016-11-14 15:54:32 +00001146 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
dp-arm90d2f0e2016-11-14 15:54:32 +00001147 if (desc->action != DO_REMOVE)
dp-arm4972ec52016-05-25 16:20:20 +01001148 continue;
dp-arm516dfcb2016-11-03 13:59:26 +00001149
dp-armafa1efa2017-02-14 15:22:13 +00001150 if (desc->image != NULL) {
dp-arm4972ec52016-05-25 16:20:20 +01001151 if (verbose)
dp-arm516dfcb2016-11-03 13:59:26 +00001152 log_dbgx("Removing %s",
dp-arm90d2f0e2016-11-14 15:54:32 +00001153 desc->cmdline_name);
dp-armafa1efa2017-02-14 15:22:13 +00001154 free(desc->image);
1155 desc->image = NULL;
dp-arm4972ec52016-05-25 16:20:20 +01001156 } else {
dp-arm516dfcb2016-11-03 13:59:26 +00001157 log_warnx("%s does not exist in %s",
dp-arm90d2f0e2016-11-14 15:54:32 +00001158 desc->cmdline_name, argv[0]);
dp-arm4972ec52016-05-25 16:20:20 +01001159 }
1160 }
1161
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001162 pack_images(outfile, toc_header.flags, align);
dp-arm4972ec52016-05-25 16:20:20 +01001163 return 0;
1164}
1165
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001166static void remove_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +01001167{
1168 toc_entry_t *toc_entry = toc_entries;
1169
Masahiro Yamada7abd0a22017-01-14 11:04:36 +09001170 printf("fiptool remove [opts] FIP_FILENAME\n");
1171 printf("\n");
1172 printf("Options:\n");
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001173 printf(" --align <value>\tEach image is aligned to <value> (default: 1).\n");
dp-arm516dfcb2016-11-03 13:59:26 +00001174 printf(" --blob uuid=...\tRemove an image with the given UUID.\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +09001175 printf(" --force\t\tIf the output FIP file already exists, use --force to overwrite it.\n");
dp-arm4972ec52016-05-25 16:20:20 +01001176 printf(" --out FIP_FILENAME\tSet an alternative output FIP file.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +09001177 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001178 printf("Specific images are removed with the following options:\n");
1179 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1180 printf(" --%-16s\t%s\n", toc_entry->cmdline_name,
1181 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +05301182#ifdef PLAT_DEF_FIP_UUID
1183 toc_entry = plat_def_toc_entries;
1184 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1185 printf(" --%-16s\t%s\n", toc_entry->cmdline_name,
1186 toc_entry->name);
1187#endif
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001188 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +01001189}
1190
1191static int version_cmd(int argc, char *argv[])
1192{
1193#ifdef VERSION
1194 puts(VERSION);
1195#else
1196 /* If built from fiptool directory, VERSION is not set. */
1197 puts("Unknown version");
1198#endif
1199 return 0;
1200}
1201
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001202static void version_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +01001203{
1204 printf("fiptool version\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001205 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +01001206}
1207
1208static int help_cmd(int argc, char *argv[])
1209{
1210 int i;
1211
1212 if (argc < 2)
1213 usage();
1214 argc--, argv++;
1215
1216 for (i = 0; i < NELEM(cmds); i++) {
1217 if (strcmp(cmds[i].name, argv[0]) == 0 &&
dp-arm29f1b5c2016-09-15 09:58:50 +01001218 cmds[i].usage != NULL)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001219 cmds[i].usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +01001220 }
1221 if (i == NELEM(cmds))
1222 printf("No help for subcommand '%s'\n", argv[0]);
1223 return 0;
1224}
1225
1226static void usage(void)
1227{
Masahiro Yamada252c3362017-01-13 02:13:06 +09001228 printf("usage: fiptool [--verbose] <command> [<args>]\n");
dp-arm4972ec52016-05-25 16:20:20 +01001229 printf("Global options supported:\n");
1230 printf(" --verbose\tEnable verbose output for all commands.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +09001231 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001232 printf("Commands supported:\n");
1233 printf(" info\t\tList images contained in FIP.\n");
1234 printf(" create\tCreate a new FIP with the given images.\n");
1235 printf(" update\tUpdate an existing FIP with the given images.\n");
1236 printf(" unpack\tUnpack images from FIP.\n");
1237 printf(" remove\tRemove images from FIP.\n");
1238 printf(" version\tShow fiptool version.\n");
1239 printf(" help\t\tShow help for given command.\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001240 exit(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +01001241}
1242
1243int main(int argc, char *argv[])
1244{
1245 int i, ret = 0;
1246
dp-arm5cd10ae2016-11-07 10:45:59 +00001247 while (1) {
1248 int c, opt_index = 0;
1249 static struct option opts[] = {
1250 { "verbose", no_argument, NULL, 'v' },
1251 { NULL, no_argument, NULL, 0 }
1252 };
1253
1254 /*
1255 * Set POSIX mode so getopt stops at the first non-option
1256 * which is the subcommand.
1257 */
1258 c = getopt_long(argc, argv, "+v", opts, &opt_index);
1259 if (c == -1)
1260 break;
dp-arm4972ec52016-05-25 16:20:20 +01001261
dp-arm5cd10ae2016-11-07 10:45:59 +00001262 switch (c) {
1263 case 'v':
1264 verbose = 1;
1265 break;
1266 default:
Masahiro Yamada48a24972016-10-26 13:24:26 +09001267 usage();
dp-arm5cd10ae2016-11-07 10:45:59 +00001268 }
dp-arm4972ec52016-05-25 16:20:20 +01001269 }
dp-arm5cd10ae2016-11-07 10:45:59 +00001270 argc -= optind;
1271 argv += optind;
1272 /* Reset optind for subsequent getopt processing. */
1273 optind = 0;
1274
1275 if (argc == 0)
1276 usage();
dp-arm4972ec52016-05-25 16:20:20 +01001277
dp-arm90d2f0e2016-11-14 15:54:32 +00001278 fill_image_descs();
dp-arm4972ec52016-05-25 16:20:20 +01001279 for (i = 0; i < NELEM(cmds); i++) {
1280 if (strcmp(cmds[i].name, argv[0]) == 0) {
1281 ret = cmds[i].handler(argc, argv);
1282 break;
1283 }
1284 }
1285 if (i == NELEM(cmds))
1286 usage();
dp-arm90d2f0e2016-11-14 15:54:32 +00001287 free_image_descs();
dp-arm4972ec52016-05-25 16:20:20 +01001288 return ret;
1289}