blob: fadf31929574bb9fae9cbfa324df0b25512b247f [file] [log] [blame]
dp-arm4972ec52016-05-25 16:20:20 +01001/*
Antonio Borneo16995302022-09-22 12:15:27 +02002 * Copyright (c) 2016-2023, 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
Antonio Borneo16995302022-09-22 12:15:27 +02007#ifndef _MSC_VER
8#include <sys/mount.h>
9#endif
dp-arm4972ec52016-05-25 16:20:20 +010010#include <sys/types.h>
11#include <sys/stat.h>
12
13#include <assert.h>
14#include <errno.h>
dp-arm4972ec52016-05-25 16:20:20 +010015#include <limits.h>
16#include <stdarg.h>
17#include <stdint.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
Masahiro Yamadae3a2b312017-05-08 18:29:03 +090021
dp-arm4972ec52016-05-25 16:20:20 +010022#include "fiptool.h"
dp-arm4972ec52016-05-25 16:20:20 +010023#include "tbbr_config.h"
24
25#define OPT_TOC_ENTRY 0
26#define OPT_PLAT_TOC_FLAGS 1
Masahiro Yamada4d87eb42016-12-25 13:52:22 +090027#define OPT_ALIGN 2
dp-arm4972ec52016-05-25 16:20:20 +010028
29static int info_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050030static void info_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010031static int create_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050032static void create_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010033static int update_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050034static void update_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010035static int unpack_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050036static void unpack_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010037static int remove_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050038static void remove_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010039static int version_cmd(int argc, char *argv[]);
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -050040static void version_usage(int);
dp-arm4972ec52016-05-25 16:20:20 +010041static int help_cmd(int argc, char *argv[]);
42static void usage(void);
43
44/* Available subcommands. */
45static cmd_t cmds[] = {
46 { .name = "info", .handler = info_cmd, .usage = info_usage },
47 { .name = "create", .handler = create_cmd, .usage = create_usage },
48 { .name = "update", .handler = update_cmd, .usage = update_usage },
49 { .name = "unpack", .handler = unpack_cmd, .usage = unpack_usage },
50 { .name = "remove", .handler = remove_cmd, .usage = remove_usage },
51 { .name = "version", .handler = version_cmd, .usage = version_usage },
52 { .name = "help", .handler = help_cmd, .usage = NULL },
53};
54
dp-arm90d2f0e2016-11-14 15:54:32 +000055static image_desc_t *image_desc_head;
56static size_t nr_image_descs;
Roberto Vargaseace8f12018-04-26 13:36:53 +010057static const uuid_t uuid_null;
dp-arm4972ec52016-05-25 16:20:20 +010058static int verbose;
59
dp-armc1f8e772016-11-04 10:52:25 +000060static void vlog(int prio, const char *msg, va_list ap)
dp-arm4972ec52016-05-25 16:20:20 +010061{
62 char *prefix[] = { "DEBUG", "WARN", "ERROR" };
63
64 fprintf(stderr, "%s: ", prefix[prio]);
65 vfprintf(stderr, msg, ap);
66 fputc('\n', stderr);
67}
68
dp-armc1f8e772016-11-04 10:52:25 +000069static void log_dbgx(const char *msg, ...)
dp-arm4972ec52016-05-25 16:20:20 +010070{
71 va_list ap;
72
73 va_start(ap, msg);
74 vlog(LOG_DBG, msg, ap);
75 va_end(ap);
76}
77
dp-armc1f8e772016-11-04 10:52:25 +000078static void log_warnx(const char *msg, ...)
dp-arm4972ec52016-05-25 16:20:20 +010079{
80 va_list ap;
81
82 va_start(ap, msg);
83 vlog(LOG_WARN, msg, ap);
84 va_end(ap);
85}
86
dp-armc1f8e772016-11-04 10:52:25 +000087static void log_err(const char *msg, ...)
dp-arm4972ec52016-05-25 16:20:20 +010088{
89 char buf[512];
90 va_list ap;
91
92 va_start(ap, msg);
93 snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno));
94 vlog(LOG_ERR, buf, ap);
95 va_end(ap);
96 exit(1);
97}
98
dp-armc1f8e772016-11-04 10:52:25 +000099static void log_errx(const char *msg, ...)
dp-arm4972ec52016-05-25 16:20:20 +0100100{
101 va_list ap;
102
103 va_start(ap, msg);
104 vlog(LOG_ERR, msg, ap);
105 va_end(ap);
106 exit(1);
107}
108
dp-armdb0f5e92016-11-04 10:56:25 +0000109static char *xstrdup(const char *s, const char *msg)
110{
111 char *d;
112
113 d = strdup(s);
114 if (d == NULL)
dp-arm5ba38542016-12-21 14:59:30 +0000115 log_errx("strdup: %s", msg);
dp-armdb0f5e92016-11-04 10:56:25 +0000116 return d;
117}
118
119static void *xmalloc(size_t size, const char *msg)
120{
121 void *d;
122
123 d = malloc(size);
124 if (d == NULL)
dp-arm5ba38542016-12-21 14:59:30 +0000125 log_errx("malloc: %s", msg);
dp-armdb0f5e92016-11-04 10:56:25 +0000126 return d;
127}
128
Masahiro Yamada03fdf692017-01-15 00:50:41 +0900129static void *xzalloc(size_t size, const char *msg)
130{
131 return memset(xmalloc(size, msg), 0, size);
132}
133
Masahiro Yamada23f9b9e2017-01-27 03:54:02 +0900134static void xfwrite(void *buf, size_t size, FILE *fp, const char *filename)
135{
136 if (fwrite(buf, 1, size, fp) != size)
137 log_errx("Failed to write %s", filename);
138}
139
dp-arm90d2f0e2016-11-14 15:54:32 +0000140static image_desc_t *new_image_desc(const uuid_t *uuid,
141 const char *name, const char *cmdline_name)
dp-arm4972ec52016-05-25 16:20:20 +0100142{
dp-arm90d2f0e2016-11-14 15:54:32 +0000143 image_desc_t *desc;
144
Masahiro Yamada03fdf692017-01-15 00:50:41 +0900145 desc = xzalloc(sizeof(*desc),
dp-arm90d2f0e2016-11-14 15:54:32 +0000146 "failed to allocate memory for image descriptor");
147 memcpy(&desc->uuid, uuid, sizeof(uuid_t));
148 desc->name = xstrdup(name,
149 "failed to allocate memory for image name");
150 desc->cmdline_name = xstrdup(cmdline_name,
151 "failed to allocate memory for image command line name");
152 desc->action = DO_UNSPEC;
dp-arm90d2f0e2016-11-14 15:54:32 +0000153 return desc;
dp-arm4972ec52016-05-25 16:20:20 +0100154}
155
dp-armfb732312016-12-30 09:55:48 +0000156static void set_image_desc_action(image_desc_t *desc, int action,
157 const char *arg)
158{
159 assert(desc != NULL);
160
Evan Lloyd04dc3442017-05-25 19:06:47 +0100161 if (desc->action_arg != (char *)DO_UNSPEC)
dp-armfb732312016-12-30 09:55:48 +0000162 free(desc->action_arg);
163 desc->action = action;
164 desc->action_arg = NULL;
165 if (arg != NULL)
166 desc->action_arg = xstrdup(arg,
167 "failed to allocate memory for argument");
168}
169
dp-arm90d2f0e2016-11-14 15:54:32 +0000170static void free_image_desc(image_desc_t *desc)
dp-arm4972ec52016-05-25 16:20:20 +0100171{
dp-arm90d2f0e2016-11-14 15:54:32 +0000172 free(desc->name);
173 free(desc->cmdline_name);
174 free(desc->action_arg);
Jonathan Wright242cd3c2018-05-03 15:05:09 +0100175 if (desc->image) {
176 free(desc->image->buffer);
177 free(desc->image);
178 }
dp-arm90d2f0e2016-11-14 15:54:32 +0000179 free(desc);
dp-arm4972ec52016-05-25 16:20:20 +0100180}
181
dp-arm90d2f0e2016-11-14 15:54:32 +0000182static void add_image_desc(image_desc_t *desc)
dp-arm4972ec52016-05-25 16:20:20 +0100183{
Masahiro Yamadad224b452017-01-14 23:22:02 +0900184 image_desc_t **p = &image_desc_head;
185
Masahiro Yamadad224b452017-01-14 23:22:02 +0900186 while (*p)
187 p = &(*p)->next;
188
Masahiro Yamadac2a7d9c2017-01-27 12:53:13 +0900189 assert(*p == NULL);
Masahiro Yamadad224b452017-01-14 23:22:02 +0900190 *p = desc;
dp-arm90d2f0e2016-11-14 15:54:32 +0000191 nr_image_descs++;
192}
dp-arm4972ec52016-05-25 16:20:20 +0100193
dp-arm90d2f0e2016-11-14 15:54:32 +0000194static void free_image_descs(void)
195{
196 image_desc_t *desc = image_desc_head, *tmp;
197
198 while (desc != NULL) {
199 tmp = desc->next;
200 free_image_desc(desc);
201 desc = tmp;
202 nr_image_descs--;
dp-arm4972ec52016-05-25 16:20:20 +0100203 }
dp-arm90d2f0e2016-11-14 15:54:32 +0000204 assert(nr_image_descs == 0);
dp-arm4972ec52016-05-25 16:20:20 +0100205}
206
dp-arm90d2f0e2016-11-14 15:54:32 +0000207static void fill_image_descs(void)
208{
209 toc_entry_t *toc_entry;
210
211 for (toc_entry = toc_entries;
212 toc_entry->cmdline_name != NULL;
213 toc_entry++) {
214 image_desc_t *desc;
215
216 desc = new_image_desc(&toc_entry->uuid,
217 toc_entry->name,
218 toc_entry->cmdline_name);
219 add_image_desc(desc);
220 }
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +0530221#ifdef PLAT_DEF_FIP_UUID
222 for (toc_entry = plat_def_toc_entries;
223 toc_entry->cmdline_name != NULL;
224 toc_entry++) {
225 image_desc_t *desc;
226
227 desc = new_image_desc(&toc_entry->uuid,
228 toc_entry->name,
229 toc_entry->cmdline_name);
230 add_image_desc(desc);
231 }
232#endif
dp-arm90d2f0e2016-11-14 15:54:32 +0000233}
234
dp-arm90d2f0e2016-11-14 15:54:32 +0000235static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid)
dp-arm4972ec52016-05-25 16:20:20 +0100236{
dp-arm90d2f0e2016-11-14 15:54:32 +0000237 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100238
dp-arm90d2f0e2016-11-14 15:54:32 +0000239 for (desc = image_desc_head; desc != NULL; desc = desc->next)
240 if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
241 return desc;
dp-arm4972ec52016-05-25 16:20:20 +0100242 return NULL;
243}
244
dp-arm90d2f0e2016-11-14 15:54:32 +0000245static image_desc_t *lookup_image_desc_from_opt(const char *opt)
246{
247 image_desc_t *desc;
248
249 for (desc = image_desc_head; desc != NULL; desc = desc->next)
250 if (strcmp(desc->cmdline_name, opt) == 0)
251 return desc;
252 return NULL;
253}
254
dp-arm516dfcb2016-11-03 13:59:26 +0000255static void uuid_to_str(char *s, size_t len, const uuid_t *u)
256{
257 assert(len >= (_UUID_STR_LEN + 1));
258
Roberto Vargaseace8f12018-04-26 13:36:53 +0100259 snprintf(s, len,
260 "%02X%02X%02X%02X-%02X%02X-%02X%02X-%04X-%04X%04X%04X",
261 u->time_low[0], u->time_low[1], u->time_low[2], u->time_low[3],
262 u->time_mid[0], u->time_mid[1],
263 u->time_hi_and_version[0], u->time_hi_and_version[1],
264 (u->clock_seq_hi_and_reserved << 8) | u->clock_seq_low,
265 (u->node[0] << 8) | u->node[1],
266 (u->node[2] << 8) | u->node[3],
267 (u->node[4] << 8) | u->node[5]);
dp-arm516dfcb2016-11-03 13:59:26 +0000268}
269
270static void uuid_from_str(uuid_t *u, const char *s)
271{
272 int n;
273
274 if (s == NULL)
275 log_errx("UUID cannot be NULL");
276 if (strlen(s) != _UUID_STR_LEN)
277 log_errx("Invalid UUID: %s", s);
278
279 n = sscanf(s,
Roberto Vargaseace8f12018-04-26 13:36:53 +0100280 "%2hhx%2hhx%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
281 &u->time_low[0], &u->time_low[1], &u->time_low[2], &u->time_low[3],
282 &u->time_mid[0], &u->time_mid[1],
283 &u->time_hi_and_version[0], &u->time_hi_and_version[1],
284 &u->clock_seq_hi_and_reserved, &u->clock_seq_low,
285 &u->node[0], &u->node[1],
286 &u->node[2], &u->node[3],
287 &u->node[4], &u->node[5]);
dp-arm516dfcb2016-11-03 13:59:26 +0000288 /*
Andre Przywaraf41e53c2019-01-29 09:25:14 +0000289 * Given the format specifier above, we expect 16 items to be scanned
dp-arm516dfcb2016-11-03 13:59:26 +0000290 * for a properly formatted UUID.
291 */
Andre Przywaraf41e53c2019-01-29 09:25:14 +0000292 if (n != 16)
dp-arm516dfcb2016-11-03 13:59:26 +0000293 log_errx("Invalid UUID: %s", s);
294}
295
dp-armc1f8e772016-11-04 10:52:25 +0000296static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
dp-arm4972ec52016-05-25 16:20:20 +0100297{
Evan Lloyd04dc3442017-05-25 19:06:47 +0100298 struct BLD_PLAT_STAT st;
dp-arm4972ec52016-05-25 16:20:20 +0100299 FILE *fp;
300 char *buf, *bufend;
301 fip_toc_header_t *toc_header;
302 fip_toc_entry_t *toc_entry;
dp-arm4972ec52016-05-25 16:20:20 +0100303 int terminated = 0;
Antonio Borneo16995302022-09-22 12:15:27 +0200304 size_t st_size;
dp-arm4972ec52016-05-25 16:20:20 +0100305
Evan Lloydb1939392017-01-13 14:13:09 +0000306 fp = fopen(filename, "rb");
dp-arm4972ec52016-05-25 16:20:20 +0100307 if (fp == NULL)
308 log_err("fopen %s", filename);
309
310 if (fstat(fileno(fp), &st) == -1)
311 log_err("fstat %s", filename);
312
Antonio Borneo16995302022-09-22 12:15:27 +0200313 st_size = st.st_size;
314
315#ifdef BLKGETSIZE64
316 if ((st.st_mode & S_IFBLK) != 0)
317 if (ioctl(fileno(fp), BLKGETSIZE64, &st_size) == -1)
318 log_err("ioctl %s", filename);
319#endif
320
321 buf = xmalloc(st_size, "failed to load file into memory");
322 if (fread(buf, 1, st_size, fp) != st_size)
dp-arm4972ec52016-05-25 16:20:20 +0100323 log_errx("Failed to read %s", filename);
Antonio Borneo16995302022-09-22 12:15:27 +0200324 bufend = buf + st_size;
dp-arm4972ec52016-05-25 16:20:20 +0100325 fclose(fp);
326
Antonio Borneo16995302022-09-22 12:15:27 +0200327 if (st_size < sizeof(fip_toc_header_t))
dp-arm4972ec52016-05-25 16:20:20 +0100328 log_errx("FIP %s is truncated", filename);
329
330 toc_header = (fip_toc_header_t *)buf;
331 toc_entry = (fip_toc_entry_t *)(toc_header + 1);
332
333 if (toc_header->name != TOC_HEADER_NAME)
334 log_errx("%s is not a FIP file", filename);
335
336 /* Return the ToC header if the caller wants it. */
337 if (toc_header_out != NULL)
338 *toc_header_out = *toc_header;
339
340 /* Walk through each ToC entry in the file. */
341 while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) {
dp-arm516dfcb2016-11-03 13:59:26 +0000342 image_t *image;
343 image_desc_t *desc;
344
dp-arm4972ec52016-05-25 16:20:20 +0100345 /* Found the ToC terminator, we are done. */
346 if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) {
347 terminated = 1;
348 break;
349 }
350
351 /*
352 * Build a new image out of the ToC entry and add it to the
353 * table of images.
354 */
Masahiro Yamadad224b452017-01-14 23:22:02 +0900355 image = xzalloc(sizeof(*image),
dp-armdb0f5e92016-11-04 10:56:25 +0000356 "failed to allocate memory for image");
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900357 image->toc_e = *toc_entry;
dp-armdb0f5e92016-11-04 10:56:25 +0000358 image->buffer = xmalloc(toc_entry->size,
359 "failed to allocate image buffer, is FIP file corrupted?");
dp-arm4972ec52016-05-25 16:20:20 +0100360 /* Overflow checks before memory copy. */
361 if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address)
Antonio Borneo16995302022-09-22 12:15:27 +0200362 log_errx("FIP %s is corrupted: entry size exceeds 64 bit address space",
363 filename);
364 if (toc_entry->size + toc_entry->offset_address > st_size)
365 log_errx("FIP %s is corrupted: entry size exceeds FIP file size",
366 filename);
dp-arm4972ec52016-05-25 16:20:20 +0100367
368 memcpy(image->buffer, buf + toc_entry->offset_address,
369 toc_entry->size);
dp-arm4972ec52016-05-25 16:20:20 +0100370
dp-arm516dfcb2016-11-03 13:59:26 +0000371 /* If this is an unknown image, create a descriptor for it. */
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900372 desc = lookup_image_desc_from_uuid(&toc_entry->uuid);
dp-arm516dfcb2016-11-03 13:59:26 +0000373 if (desc == NULL) {
374 char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
375
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900376 uuid_to_str(name, sizeof(name), &toc_entry->uuid);
dp-arm516dfcb2016-11-03 13:59:26 +0000377 snprintf(filename, sizeof(filename), "%s%s",
378 name, ".bin");
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900379 desc = new_image_desc(&toc_entry->uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000380 desc->action = DO_UNPACK;
381 desc->action_arg = xstrdup(filename,
382 "failed to allocate memory for blob filename");
383 add_image_desc(desc);
384 }
385
dp-armafa1efa2017-02-14 15:22:13 +0000386 assert(desc->image == NULL);
387 desc->image = image;
dp-arm4972ec52016-05-25 16:20:20 +0100388
389 toc_entry++;
390 }
391
392 if (terminated == 0)
393 log_errx("FIP %s does not have a ToC terminator entry",
394 filename);
395 free(buf);
396 return 0;
397}
398
dp-armc1f8e772016-11-04 10:52:25 +0000399static image_t *read_image_from_file(const uuid_t *uuid, const char *filename)
dp-arm4972ec52016-05-25 16:20:20 +0100400{
Evan Lloyd04dc3442017-05-25 19:06:47 +0100401 struct BLD_PLAT_STAT st;
dp-arm4972ec52016-05-25 16:20:20 +0100402 image_t *image;
403 FILE *fp;
404
dp-arm715ef422016-08-30 14:18:58 +0100405 assert(uuid != NULL);
Evan Lloyd04dc3442017-05-25 19:06:47 +0100406 assert(filename != NULL);
dp-arm715ef422016-08-30 14:18:58 +0100407
Evan Lloydb1939392017-01-13 14:13:09 +0000408 fp = fopen(filename, "rb");
dp-arm4972ec52016-05-25 16:20:20 +0100409 if (fp == NULL)
410 log_err("fopen %s", filename);
411
412 if (fstat(fileno(fp), &st) == -1)
413 log_errx("fstat %s", filename);
414
Masahiro Yamadad224b452017-01-14 23:22:02 +0900415 image = xzalloc(sizeof(*image), "failed to allocate memory for image");
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900416 image->toc_e.uuid = *uuid;
dp-armdb0f5e92016-11-04 10:56:25 +0000417 image->buffer = xmalloc(st.st_size, "failed to allocate image buffer");
dp-arm4972ec52016-05-25 16:20:20 +0100418 if (fread(image->buffer, 1, st.st_size, fp) != st.st_size)
419 log_errx("Failed to read %s", filename);
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900420 image->toc_e.size = st.st_size;
dp-arm4972ec52016-05-25 16:20:20 +0100421
422 fclose(fp);
423 return image;
424}
425
dp-armc1f8e772016-11-04 10:52:25 +0000426static int write_image_to_file(const image_t *image, const char *filename)
dp-arm4972ec52016-05-25 16:20:20 +0100427{
428 FILE *fp;
429
Evan Lloydb1939392017-01-13 14:13:09 +0000430 fp = fopen(filename, "wb");
dp-arm4972ec52016-05-25 16:20:20 +0100431 if (fp == NULL)
432 log_err("fopen");
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900433 xfwrite(image->buffer, image->toc_e.size, fp, filename);
dp-arm4972ec52016-05-25 16:20:20 +0100434 fclose(fp);
435 return 0;
436}
437
dp-arm90d2f0e2016-11-14 15:54:32 +0000438static struct option *add_opt(struct option *opts, size_t *nr_opts,
439 const char *name, int has_arg, int val)
dp-arm4972ec52016-05-25 16:20:20 +0100440{
dp-arm90d2f0e2016-11-14 15:54:32 +0000441 opts = realloc(opts, (*nr_opts + 1) * sizeof(*opts));
442 if (opts == NULL)
443 log_err("realloc");
444 opts[*nr_opts].name = name;
445 opts[*nr_opts].has_arg = has_arg;
446 opts[*nr_opts].flag = NULL;
447 opts[*nr_opts].val = val;
448 ++*nr_opts;
449 return opts;
dp-arm4972ec52016-05-25 16:20:20 +0100450}
451
dp-arm90d2f0e2016-11-14 15:54:32 +0000452static struct option *fill_common_opts(struct option *opts, size_t *nr_opts,
453 int has_arg)
dp-arm4972ec52016-05-25 16:20:20 +0100454{
dp-arm90d2f0e2016-11-14 15:54:32 +0000455 image_desc_t *desc;
456
457 for (desc = image_desc_head; desc != NULL; desc = desc->next)
458 opts = add_opt(opts, nr_opts, desc->cmdline_name, has_arg,
459 OPT_TOC_ENTRY);
460 return opts;
dp-arm4972ec52016-05-25 16:20:20 +0100461}
462
dp-arm90d2f0e2016-11-14 15:54:32 +0000463static void md_print(const unsigned char *md, size_t len)
dp-arm12e893b2016-08-24 13:21:08 +0100464{
465 size_t i;
466
467 for (i = 0; i < len; i++)
468 printf("%02x", md[i]);
469}
470
dp-arm4972ec52016-05-25 16:20:20 +0100471static int info_cmd(int argc, char *argv[])
472{
dp-armafa1efa2017-02-14 15:22:13 +0000473 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100474 fip_toc_header_t toc_header;
dp-arm4972ec52016-05-25 16:20:20 +0100475
476 if (argc != 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500477 info_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100478 argc--, argv++;
479
480 parse_fip(argv[0], &toc_header);
481
482 if (verbose) {
483 log_dbgx("toc_header[name]: 0x%llX",
484 (unsigned long long)toc_header.name);
485 log_dbgx("toc_header[serial_number]: 0x%llX",
486 (unsigned long long)toc_header.serial_number);
487 log_dbgx("toc_header[flags]: 0x%llX",
488 (unsigned long long)toc_header.flags);
489 }
490
dp-armafa1efa2017-02-14 15:22:13 +0000491 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
492 image_t *image = desc->image;
dp-arm715ef422016-08-30 14:18:58 +0100493
dp-armafa1efa2017-02-14 15:22:13 +0000494 if (image == NULL)
495 continue;
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900496 printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"--%s\"",
497 desc->name,
498 (unsigned long long)image->toc_e.offset_address,
499 (unsigned long long)image->toc_e.size,
Masahiro Yamadaeee39312017-01-15 23:20:00 +0900500 desc->cmdline_name);
Evan Lloyd04dc3442017-05-25 19:06:47 +0100501#ifndef _MSC_VER /* We don't have SHA256 for Visual Studio. */
dp-arm12e893b2016-08-24 13:21:08 +0100502 if (verbose) {
503 unsigned char md[SHA256_DIGEST_LENGTH];
504
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900505 SHA256(image->buffer, image->toc_e.size, md);
dp-arm12e893b2016-08-24 13:21:08 +0100506 printf(", sha256=");
507 md_print(md, sizeof(md));
508 }
Evan Lloyd04dc3442017-05-25 19:06:47 +0100509#endif
dp-arm12e893b2016-08-24 13:21:08 +0100510 putchar('\n');
dp-arm4972ec52016-05-25 16:20:20 +0100511 }
512
dp-arm4972ec52016-05-25 16:20:20 +0100513 return 0;
514}
515
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500516static void info_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +0100517{
518 printf("fiptool info FIP_FILENAME\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500519 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +0100520}
521
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900522static int pack_images(const char *filename, uint64_t toc_flags, unsigned long align)
dp-arm4972ec52016-05-25 16:20:20 +0100523{
524 FILE *fp;
dp-armafa1efa2017-02-14 15:22:13 +0000525 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100526 fip_toc_header_t *toc_header;
527 fip_toc_entry_t *toc_entry;
528 char *buf;
Roberto Vargas81935762017-12-19 11:56:57 +0000529 uint64_t entry_offset, buf_size, payload_size = 0, pad_size;
dp-armafa1efa2017-02-14 15:22:13 +0000530 size_t nr_images = 0;
531
532 for (desc = image_desc_head; desc != NULL; desc = desc->next)
533 if (desc->image != NULL)
534 nr_images++;
dp-arm4972ec52016-05-25 16:20:20 +0100535
536 buf_size = sizeof(fip_toc_header_t) +
537 sizeof(fip_toc_entry_t) * (nr_images + 1);
538 buf = calloc(1, buf_size);
539 if (buf == NULL)
540 log_err("calloc");
541
542 /* Build up header and ToC entries from the image table. */
543 toc_header = (fip_toc_header_t *)buf;
544 toc_header->name = TOC_HEADER_NAME;
545 toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
546 toc_header->flags = toc_flags;
547
548 toc_entry = (fip_toc_entry_t *)(toc_header + 1);
549
550 entry_offset = buf_size;
dp-armafa1efa2017-02-14 15:22:13 +0000551 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
552 image_t *image = desc->image;
553
Manish V Badarkhe0624d732021-12-18 11:26:25 +0000554 if (image == NULL || (image->toc_e.size == 0ULL))
dp-armafa1efa2017-02-14 15:22:13 +0000555 continue;
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900556 payload_size += image->toc_e.size;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900557 entry_offset = (entry_offset + align - 1) & ~(align - 1);
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900558 image->toc_e.offset_address = entry_offset;
559 *toc_entry++ = image->toc_e;
560 entry_offset += image->toc_e.size;
dp-arm4972ec52016-05-25 16:20:20 +0100561 }
562
Roberto Vargas81935762017-12-19 11:56:57 +0000563 /*
564 * Append a null uuid entry to mark the end of ToC entries.
565 * NOTE the offset address for the last toc_entry must match the fip
566 * size.
567 */
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900568 memset(toc_entry, 0, sizeof(*toc_entry));
Roberto Vargas81935762017-12-19 11:56:57 +0000569 toc_entry->offset_address = (entry_offset + align - 1) & ~(align - 1);
dp-arm4972ec52016-05-25 16:20:20 +0100570
571 /* Generate the FIP file. */
Evan Lloydb1939392017-01-13 14:13:09 +0000572 fp = fopen(filename, "wb");
dp-arm4972ec52016-05-25 16:20:20 +0100573 if (fp == NULL)
574 log_err("fopen %s", filename);
575
576 if (verbose)
577 log_dbgx("Metadata size: %zu bytes", buf_size);
578
Masahiro Yamada23f9b9e2017-01-27 03:54:02 +0900579 xfwrite(buf, buf_size, fp, filename);
dp-arm4972ec52016-05-25 16:20:20 +0100580
581 if (verbose)
582 log_dbgx("Payload size: %zu bytes", payload_size);
583
dp-armafa1efa2017-02-14 15:22:13 +0000584 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
585 image_t *image = desc->image;
586
587 if (image == NULL)
588 continue;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900589 if (fseek(fp, image->toc_e.offset_address, SEEK_SET))
590 log_errx("Failed to set file position");
591
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900592 xfwrite(image->buffer, image->toc_e.size, fp, filename);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900593 }
dp-arm4972ec52016-05-25 16:20:20 +0100594
Roberto Vargas81935762017-12-19 11:56:57 +0000595 if (fseek(fp, entry_offset, SEEK_SET))
596 log_errx("Failed to set file position");
597
598 pad_size = toc_entry->offset_address - entry_offset;
599 while (pad_size--)
600 fputc(0x0, fp);
601
Andreas Färber860b5dc2018-01-27 16:46:59 +0100602 free(buf);
dp-arm4972ec52016-05-25 16:20:20 +0100603 fclose(fp);
604 return 0;
605}
606
607/*
608 * This function is shared between the create and update subcommands.
609 * The difference between the two subcommands is that when the FIP file
610 * is created, the parsing of an existing FIP is skipped. This results
611 * in update_fip() creating the new FIP file from scratch because the
612 * internal image table is not populated.
613 */
614static void update_fip(void)
615{
dp-arm90d2f0e2016-11-14 15:54:32 +0000616 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100617
618 /* Add or replace images in the FIP file. */
dp-arm90d2f0e2016-11-14 15:54:32 +0000619 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
dp-armafa1efa2017-02-14 15:22:13 +0000620 image_t *image;
dp-arm516dfcb2016-11-03 13:59:26 +0000621
dp-arm90d2f0e2016-11-14 15:54:32 +0000622 if (desc->action != DO_PACK)
dp-arm4972ec52016-05-25 16:20:20 +0100623 continue;
624
dp-armafa1efa2017-02-14 15:22:13 +0000625 image = read_image_from_file(&desc->uuid,
dp-arm90d2f0e2016-11-14 15:54:32 +0000626 desc->action_arg);
dp-armafa1efa2017-02-14 15:22:13 +0000627 if (desc->image != NULL) {
dp-arm90d2f0e2016-11-14 15:54:32 +0000628 if (verbose) {
dp-arm516dfcb2016-11-03 13:59:26 +0000629 log_dbgx("Replacing %s with %s",
dp-arm90d2f0e2016-11-14 15:54:32 +0000630 desc->cmdline_name,
631 desc->action_arg);
632 }
dp-armafa1efa2017-02-14 15:22:13 +0000633 free(desc->image);
634 desc->image = image;
dp-arm4972ec52016-05-25 16:20:20 +0100635 } else {
636 if (verbose)
637 log_dbgx("Adding image %s",
dp-arm90d2f0e2016-11-14 15:54:32 +0000638 desc->action_arg);
dp-armafa1efa2017-02-14 15:22:13 +0000639 desc->image = image;
dp-arm4972ec52016-05-25 16:20:20 +0100640 }
dp-arm4972ec52016-05-25 16:20:20 +0100641 }
642}
643
dp-arm90d2f0e2016-11-14 15:54:32 +0000644static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags)
dp-arm4972ec52016-05-25 16:20:20 +0100645{
646 unsigned long long flags;
647 char *endptr;
648
649 errno = 0;
650 flags = strtoull(arg, &endptr, 16);
651 if (*endptr != '\0' || flags > UINT16_MAX || errno != 0)
652 log_errx("Invalid platform ToC flags: %s", arg);
653 /* Platform ToC flags is a 16-bit field occupying bits [32-47]. */
654 *toc_flags |= flags << 32;
655}
656
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900657static int is_power_of_2(unsigned long x)
658{
659 return x && !(x & (x - 1));
660}
661
662static unsigned long get_image_align(char *arg)
663{
664 char *endptr;
665 unsigned long align;
666
667 errno = 0;
Andreas Färber242a7b72017-04-21 19:39:10 +0200668 align = strtoul(arg, &endptr, 0);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900669 if (*endptr != '\0' || !is_power_of_2(align) || errno != 0)
670 log_errx("Invalid alignment: %s", arg);
671
672 return align;
673}
674
dp-arm516dfcb2016-11-03 13:59:26 +0000675static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len)
676{
677 char *p;
678
679 for (p = strtok(arg, ","); p != NULL; p = strtok(NULL, ",")) {
680 if (strncmp(p, "uuid=", strlen("uuid=")) == 0) {
681 p += strlen("uuid=");
682 uuid_from_str(uuid, p);
683 } else if (strncmp(p, "file=", strlen("file=")) == 0) {
684 p += strlen("file=");
685 snprintf(filename, len, "%s", p);
686 }
687 }
688}
689
dp-arm4972ec52016-05-25 16:20:20 +0100690static int create_cmd(int argc, char *argv[])
691{
dp-arm90d2f0e2016-11-14 15:54:32 +0000692 struct option *opts = NULL;
693 size_t nr_opts = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100694 unsigned long long toc_flags = 0;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900695 unsigned long align = 1;
dp-arm4972ec52016-05-25 16:20:20 +0100696
697 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500698 create_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100699
dp-arm90d2f0e2016-11-14 15:54:32 +0000700 opts = fill_common_opts(opts, &nr_opts, required_argument);
701 opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
dp-arm4972ec52016-05-25 16:20:20 +0100702 OPT_PLAT_TOC_FLAGS);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900703 opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
dp-arm516dfcb2016-11-03 13:59:26 +0000704 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +0000705 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +0100706
707 while (1) {
dp-armfe92b892016-11-07 11:13:54 +0000708 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100709
dp-arm516dfcb2016-11-03 13:59:26 +0000710 c = getopt_long(argc, argv, "b:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +0100711 if (c == -1)
712 break;
713
714 switch (c) {
715 case OPT_TOC_ENTRY: {
dp-arm90d2f0e2016-11-14 15:54:32 +0000716 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100717
dp-arm90d2f0e2016-11-14 15:54:32 +0000718 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +0000719 set_image_desc_action(desc, DO_PACK, optarg);
dp-arm4972ec52016-05-25 16:20:20 +0100720 break;
721 }
722 case OPT_PLAT_TOC_FLAGS:
723 parse_plat_toc_flags(optarg, &toc_flags);
724 break;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900725 case OPT_ALIGN:
726 align = get_image_align(optarg);
727 break;
dp-arm516dfcb2016-11-03 13:59:26 +0000728 case 'b': {
729 char name[_UUID_STR_LEN + 1];
730 char filename[PATH_MAX] = { 0 };
Roberto Vargaseace8f12018-04-26 13:36:53 +0100731 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +0000732 image_desc_t *desc;
733
734 parse_blob_opt(optarg, &uuid,
735 filename, sizeof(filename));
736
737 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
738 filename[0] == '\0')
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500739 create_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +0000740
741 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +0000742 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +0000743 uuid_to_str(name, sizeof(name), &uuid);
744 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000745 add_image_desc(desc);
746 }
dp-armfb732312016-12-30 09:55:48 +0000747 set_image_desc_action(desc, DO_PACK, filename);
dp-arm516dfcb2016-11-03 13:59:26 +0000748 break;
749 }
dp-arm4972ec52016-05-25 16:20:20 +0100750 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500751 create_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100752 }
753 }
754 argc -= optind;
755 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +0000756 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +0100757
758 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500759 create_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +0100760
761 update_fip();
762
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900763 pack_images(argv[0], toc_flags, align);
dp-arm4972ec52016-05-25 16:20:20 +0100764 return 0;
765}
766
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500767static void create_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +0100768{
769 toc_entry_t *toc_entry = toc_entries;
770
Masahiro Yamada7abd0a22017-01-14 11:04:36 +0900771 printf("fiptool create [opts] FIP_FILENAME\n");
772 printf("\n");
773 printf("Options:\n");
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900774 printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +0900775 printf(" --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n");
776 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 +0900777 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +0100778 printf("Specific images are packed with the following options:\n");
779 for (; toc_entry->cmdline_name != NULL; toc_entry++)
780 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
781 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +0530782#ifdef PLAT_DEF_FIP_UUID
783 toc_entry = plat_def_toc_entries;
784 for (; toc_entry->cmdline_name != NULL; toc_entry++)
785 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
786 toc_entry->name);
787#endif
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500788 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +0100789}
790
791static int update_cmd(int argc, char *argv[])
792{
dp-arm90d2f0e2016-11-14 15:54:32 +0000793 struct option *opts = NULL;
794 size_t nr_opts = 0;
dp-arm516dfcb2016-11-03 13:59:26 +0000795 char outfile[PATH_MAX] = { 0 };
dp-arm4972ec52016-05-25 16:20:20 +0100796 fip_toc_header_t toc_header = { 0 };
797 unsigned long long toc_flags = 0;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900798 unsigned long align = 1;
dp-arm4972ec52016-05-25 16:20:20 +0100799 int pflag = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100800
801 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500802 update_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100803
dp-arm90d2f0e2016-11-14 15:54:32 +0000804 opts = fill_common_opts(opts, &nr_opts, required_argument);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900805 opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
dp-arm516dfcb2016-11-03 13:59:26 +0000806 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +0000807 opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
808 opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
dp-arm4972ec52016-05-25 16:20:20 +0100809 OPT_PLAT_TOC_FLAGS);
dp-arm90d2f0e2016-11-14 15:54:32 +0000810 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +0100811
812 while (1) {
dp-armfe92b892016-11-07 11:13:54 +0000813 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100814
dp-arm516dfcb2016-11-03 13:59:26 +0000815 c = getopt_long(argc, argv, "b:o:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +0100816 if (c == -1)
817 break;
818
819 switch (c) {
820 case OPT_TOC_ENTRY: {
dp-arm90d2f0e2016-11-14 15:54:32 +0000821 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100822
dp-arm90d2f0e2016-11-14 15:54:32 +0000823 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +0000824 set_image_desc_action(desc, DO_PACK, optarg);
dp-arm4972ec52016-05-25 16:20:20 +0100825 break;
826 }
dp-arm90d2f0e2016-11-14 15:54:32 +0000827 case OPT_PLAT_TOC_FLAGS:
dp-arm4972ec52016-05-25 16:20:20 +0100828 parse_plat_toc_flags(optarg, &toc_flags);
829 pflag = 1;
830 break;
dp-arm516dfcb2016-11-03 13:59:26 +0000831 case 'b': {
832 char name[_UUID_STR_LEN + 1];
833 char filename[PATH_MAX] = { 0 };
Roberto Vargaseace8f12018-04-26 13:36:53 +0100834 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +0000835 image_desc_t *desc;
836
837 parse_blob_opt(optarg, &uuid,
838 filename, sizeof(filename));
839
840 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
841 filename[0] == '\0')
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500842 update_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +0000843
844 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +0000845 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +0000846 uuid_to_str(name, sizeof(name), &uuid);
847 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000848 add_image_desc(desc);
849 }
dp-armfb732312016-12-30 09:55:48 +0000850 set_image_desc_action(desc, DO_PACK, filename);
dp-arm516dfcb2016-11-03 13:59:26 +0000851 break;
852 }
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900853 case OPT_ALIGN:
854 align = get_image_align(optarg);
855 break;
dp-arm4972ec52016-05-25 16:20:20 +0100856 case 'o':
857 snprintf(outfile, sizeof(outfile), "%s", optarg);
858 break;
859 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500860 update_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100861 }
862 }
863 argc -= optind;
864 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +0000865 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +0100866
867 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500868 update_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +0100869
870 if (outfile[0] == '\0')
871 snprintf(outfile, sizeof(outfile), "%s", argv[0]);
872
Masahiro Yamadaebb6e372016-12-25 12:41:41 +0900873 if (access(argv[0], F_OK) == 0)
dp-arm4972ec52016-05-25 16:20:20 +0100874 parse_fip(argv[0], &toc_header);
875
876 if (pflag)
877 toc_header.flags &= ~(0xffffULL << 32);
878 toc_flags = (toc_header.flags |= toc_flags);
879
880 update_fip();
881
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900882 pack_images(outfile, toc_flags, align);
dp-arm4972ec52016-05-25 16:20:20 +0100883 return 0;
884}
885
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500886static void update_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +0100887{
888 toc_entry_t *toc_entry = toc_entries;
889
Masahiro Yamada7abd0a22017-01-14 11:04:36 +0900890 printf("fiptool update [opts] FIP_FILENAME\n");
891 printf("\n");
892 printf("Options:\n");
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900893 printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +0900894 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 +0100895 printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +0900896 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 +0900897 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +0100898 printf("Specific images are packed with the following options:\n");
899 for (; toc_entry->cmdline_name != NULL; toc_entry++)
900 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
901 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +0530902#ifdef PLAT_DEF_FIP_UUID
903 toc_entry = plat_def_toc_entries;
904 for (; toc_entry->cmdline_name != NULL; toc_entry++)
905 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
906 toc_entry->name);
907#endif
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500908 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +0100909}
910
911static int unpack_cmd(int argc, char *argv[])
912{
dp-arm90d2f0e2016-11-14 15:54:32 +0000913 struct option *opts = NULL;
914 size_t nr_opts = 0;
dp-arm516dfcb2016-11-03 13:59:26 +0000915 char outdir[PATH_MAX] = { 0 };
dp-arm90d2f0e2016-11-14 15:54:32 +0000916 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100917 int fflag = 0;
918 int unpack_all = 1;
dp-arm4972ec52016-05-25 16:20:20 +0100919
920 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500921 unpack_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100922
dp-arm90d2f0e2016-11-14 15:54:32 +0000923 opts = fill_common_opts(opts, &nr_opts, required_argument);
dp-arm516dfcb2016-11-03 13:59:26 +0000924 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +0000925 opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
926 opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
927 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +0100928
929 while (1) {
dp-armfe92b892016-11-07 11:13:54 +0000930 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100931
dp-arm516dfcb2016-11-03 13:59:26 +0000932 c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +0100933 if (c == -1)
934 break;
935
936 switch (c) {
dp-arm90d2f0e2016-11-14 15:54:32 +0000937 case OPT_TOC_ENTRY: {
938 image_desc_t *desc;
939
940 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +0000941 set_image_desc_action(desc, DO_UNPACK, optarg);
dp-arm90d2f0e2016-11-14 15:54:32 +0000942 unpack_all = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100943 break;
dp-arm90d2f0e2016-11-14 15:54:32 +0000944 }
dp-arm516dfcb2016-11-03 13:59:26 +0000945 case 'b': {
946 char name[_UUID_STR_LEN + 1];
947 char filename[PATH_MAX] = { 0 };
Roberto Vargaseace8f12018-04-26 13:36:53 +0100948 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +0000949 image_desc_t *desc;
950
951 parse_blob_opt(optarg, &uuid,
952 filename, sizeof(filename));
953
954 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
955 filename[0] == '\0')
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500956 unpack_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +0000957
958 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +0000959 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +0000960 uuid_to_str(name, sizeof(name), &uuid);
961 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000962 add_image_desc(desc);
963 }
dp-armfb732312016-12-30 09:55:48 +0000964 set_image_desc_action(desc, DO_UNPACK, filename);
dp-arm516dfcb2016-11-03 13:59:26 +0000965 unpack_all = 0;
966 break;
967 }
dp-arm4972ec52016-05-25 16:20:20 +0100968 case 'f':
969 fflag = 1;
970 break;
971 case 'o':
972 snprintf(outdir, sizeof(outdir), "%s", optarg);
973 break;
974 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500975 unpack_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100976 }
977 }
978 argc -= optind;
979 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +0000980 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +0100981
982 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500983 unpack_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +0100984
985 parse_fip(argv[0], NULL);
986
987 if (outdir[0] != '\0')
988 if (chdir(outdir) == -1)
989 log_err("chdir %s", outdir);
990
dp-arm4972ec52016-05-25 16:20:20 +0100991 /* Unpack all specified images. */
dp-arm90d2f0e2016-11-14 15:54:32 +0000992 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
dp-arm516dfcb2016-11-03 13:59:26 +0000993 char file[PATH_MAX];
dp-armafa1efa2017-02-14 15:22:13 +0000994 image_t *image = desc->image;
dp-arm715ef422016-08-30 14:18:58 +0100995
dp-arm90d2f0e2016-11-14 15:54:32 +0000996 if (!unpack_all && desc->action != DO_UNPACK)
dp-arm4972ec52016-05-25 16:20:20 +0100997 continue;
998
999 /* Build filename. */
dp-arm90d2f0e2016-11-14 15:54:32 +00001000 if (desc->action_arg == NULL)
dp-arm4972ec52016-05-25 16:20:20 +01001001 snprintf(file, sizeof(file), "%s.bin",
dp-arm90d2f0e2016-11-14 15:54:32 +00001002 desc->cmdline_name);
dp-arm4972ec52016-05-25 16:20:20 +01001003 else
1004 snprintf(file, sizeof(file), "%s",
dp-arm90d2f0e2016-11-14 15:54:32 +00001005 desc->action_arg);
dp-arm4972ec52016-05-25 16:20:20 +01001006
dp-arm715ef422016-08-30 14:18:58 +01001007 if (image == NULL) {
1008 if (!unpack_all)
dp-arm516dfcb2016-11-03 13:59:26 +00001009 log_warnx("%s does not exist in %s",
dp-arm715ef422016-08-30 14:18:58 +01001010 file, argv[0]);
dp-arm4972ec52016-05-25 16:20:20 +01001011 continue;
1012 }
1013
1014 if (access(file, F_OK) != 0 || fflag) {
1015 if (verbose)
1016 log_dbgx("Unpacking %s", file);
dp-arm715ef422016-08-30 14:18:58 +01001017 write_image_to_file(image, file);
dp-arm4972ec52016-05-25 16:20:20 +01001018 } else {
1019 log_warnx("File %s already exists, use --force to overwrite it",
1020 file);
1021 }
dp-arm4972ec52016-05-25 16:20:20 +01001022 }
1023
dp-arm4972ec52016-05-25 16:20:20 +01001024 return 0;
1025}
1026
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001027static void unpack_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +01001028{
1029 toc_entry_t *toc_entry = toc_entries;
1030
Masahiro Yamada7abd0a22017-01-14 11:04:36 +09001031 printf("fiptool unpack [opts] FIP_FILENAME\n");
1032 printf("\n");
1033 printf("Options:\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +09001034 printf(" --blob uuid=...,file=...\tUnpack an image with the given UUID to file.\n");
1035 printf(" --force\t\t\tIf the output file already exists, use --force to overwrite it.\n");
dp-arm516dfcb2016-11-03 13:59:26 +00001036 printf(" --out path\t\t\tSet the output directory path.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +09001037 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001038 printf("Specific images are unpacked with the following options:\n");
1039 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1040 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
1041 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +05301042#ifdef PLAT_DEF_FIP_UUID
1043 toc_entry = plat_def_toc_entries;
1044 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1045 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
1046 toc_entry->name);
1047#endif
Masahiro Yamada1b900152017-02-02 16:34:14 +09001048 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001049 printf("If no options are provided, all images will be unpacked.\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001050 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +01001051}
1052
1053static int remove_cmd(int argc, char *argv[])
1054{
dp-arm90d2f0e2016-11-14 15:54:32 +00001055 struct option *opts = NULL;
1056 size_t nr_opts = 0;
dp-arm516dfcb2016-11-03 13:59:26 +00001057 char outfile[PATH_MAX] = { 0 };
dp-arm4972ec52016-05-25 16:20:20 +01001058 fip_toc_header_t toc_header;
dp-arm90d2f0e2016-11-14 15:54:32 +00001059 image_desc_t *desc;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001060 unsigned long align = 1;
dp-arm4972ec52016-05-25 16:20:20 +01001061 int fflag = 0;
dp-arm4972ec52016-05-25 16:20:20 +01001062
1063 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001064 remove_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +01001065
dp-arm90d2f0e2016-11-14 15:54:32 +00001066 opts = fill_common_opts(opts, &nr_opts, no_argument);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001067 opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
dp-arm516dfcb2016-11-03 13:59:26 +00001068 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +00001069 opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
1070 opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
1071 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +01001072
1073 while (1) {
dp-armfe92b892016-11-07 11:13:54 +00001074 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +01001075
dp-arm516dfcb2016-11-03 13:59:26 +00001076 c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +01001077 if (c == -1)
1078 break;
1079
1080 switch (c) {
dp-arm90d2f0e2016-11-14 15:54:32 +00001081 case OPT_TOC_ENTRY: {
1082 image_desc_t *desc;
1083
1084 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +00001085 set_image_desc_action(desc, DO_REMOVE, NULL);
dp-arm4972ec52016-05-25 16:20:20 +01001086 break;
dp-arm90d2f0e2016-11-14 15:54:32 +00001087 }
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001088 case OPT_ALIGN:
1089 align = get_image_align(optarg);
1090 break;
dp-arm516dfcb2016-11-03 13:59:26 +00001091 case 'b': {
1092 char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
Roberto Vargaseace8f12018-04-26 13:36:53 +01001093 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +00001094 image_desc_t *desc;
1095
1096 parse_blob_opt(optarg, &uuid,
1097 filename, sizeof(filename));
1098
1099 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001100 remove_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +00001101
1102 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +00001103 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +00001104 uuid_to_str(name, sizeof(name), &uuid);
1105 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +00001106 add_image_desc(desc);
1107 }
dp-armfb732312016-12-30 09:55:48 +00001108 set_image_desc_action(desc, DO_REMOVE, NULL);
dp-arm516dfcb2016-11-03 13:59:26 +00001109 break;
1110 }
dp-arm4972ec52016-05-25 16:20:20 +01001111 case 'f':
1112 fflag = 1;
1113 break;
1114 case 'o':
1115 snprintf(outfile, sizeof(outfile), "%s", optarg);
1116 break;
1117 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001118 remove_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +01001119 }
1120 }
1121 argc -= optind;
1122 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +00001123 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +01001124
1125 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001126 remove_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +01001127
1128 if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag)
1129 log_errx("File %s already exists, use --force to overwrite it",
1130 outfile);
1131
1132 if (outfile[0] == '\0')
1133 snprintf(outfile, sizeof(outfile), "%s", argv[0]);
1134
1135 parse_fip(argv[0], &toc_header);
1136
dp-arm90d2f0e2016-11-14 15:54:32 +00001137 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
dp-arm90d2f0e2016-11-14 15:54:32 +00001138 if (desc->action != DO_REMOVE)
dp-arm4972ec52016-05-25 16:20:20 +01001139 continue;
dp-arm516dfcb2016-11-03 13:59:26 +00001140
dp-armafa1efa2017-02-14 15:22:13 +00001141 if (desc->image != NULL) {
dp-arm4972ec52016-05-25 16:20:20 +01001142 if (verbose)
dp-arm516dfcb2016-11-03 13:59:26 +00001143 log_dbgx("Removing %s",
dp-arm90d2f0e2016-11-14 15:54:32 +00001144 desc->cmdline_name);
dp-armafa1efa2017-02-14 15:22:13 +00001145 free(desc->image);
1146 desc->image = NULL;
dp-arm4972ec52016-05-25 16:20:20 +01001147 } else {
dp-arm516dfcb2016-11-03 13:59:26 +00001148 log_warnx("%s does not exist in %s",
dp-arm90d2f0e2016-11-14 15:54:32 +00001149 desc->cmdline_name, argv[0]);
dp-arm4972ec52016-05-25 16:20:20 +01001150 }
1151 }
1152
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001153 pack_images(outfile, toc_header.flags, align);
dp-arm4972ec52016-05-25 16:20:20 +01001154 return 0;
1155}
1156
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001157static void remove_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +01001158{
1159 toc_entry_t *toc_entry = toc_entries;
1160
Masahiro Yamada7abd0a22017-01-14 11:04:36 +09001161 printf("fiptool remove [opts] FIP_FILENAME\n");
1162 printf("\n");
1163 printf("Options:\n");
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001164 printf(" --align <value>\tEach image is aligned to <value> (default: 1).\n");
dp-arm516dfcb2016-11-03 13:59:26 +00001165 printf(" --blob uuid=...\tRemove an image with the given UUID.\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +09001166 printf(" --force\t\tIf the output FIP file already exists, use --force to overwrite it.\n");
dp-arm4972ec52016-05-25 16:20:20 +01001167 printf(" --out FIP_FILENAME\tSet an alternative output FIP file.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +09001168 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001169 printf("Specific images are removed with the following options:\n");
1170 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1171 printf(" --%-16s\t%s\n", toc_entry->cmdline_name,
1172 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +05301173#ifdef PLAT_DEF_FIP_UUID
1174 toc_entry = plat_def_toc_entries;
1175 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1176 printf(" --%-16s\t%s\n", toc_entry->cmdline_name,
1177 toc_entry->name);
1178#endif
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001179 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +01001180}
1181
1182static int version_cmd(int argc, char *argv[])
1183{
1184#ifdef VERSION
1185 puts(VERSION);
1186#else
1187 /* If built from fiptool directory, VERSION is not set. */
1188 puts("Unknown version");
1189#endif
1190 return 0;
1191}
1192
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001193static void version_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +01001194{
1195 printf("fiptool version\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001196 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +01001197}
1198
1199static int help_cmd(int argc, char *argv[])
1200{
1201 int i;
1202
1203 if (argc < 2)
1204 usage();
1205 argc--, argv++;
1206
1207 for (i = 0; i < NELEM(cmds); i++) {
1208 if (strcmp(cmds[i].name, argv[0]) == 0 &&
dp-arm29f1b5c2016-09-15 09:58:50 +01001209 cmds[i].usage != NULL)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001210 cmds[i].usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +01001211 }
1212 if (i == NELEM(cmds))
1213 printf("No help for subcommand '%s'\n", argv[0]);
1214 return 0;
1215}
1216
1217static void usage(void)
1218{
Masahiro Yamada252c3362017-01-13 02:13:06 +09001219 printf("usage: fiptool [--verbose] <command> [<args>]\n");
dp-arm4972ec52016-05-25 16:20:20 +01001220 printf("Global options supported:\n");
1221 printf(" --verbose\tEnable verbose output for all commands.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +09001222 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001223 printf("Commands supported:\n");
1224 printf(" info\t\tList images contained in FIP.\n");
1225 printf(" create\tCreate a new FIP with the given images.\n");
1226 printf(" update\tUpdate an existing FIP with the given images.\n");
1227 printf(" unpack\tUnpack images from FIP.\n");
1228 printf(" remove\tRemove images from FIP.\n");
1229 printf(" version\tShow fiptool version.\n");
1230 printf(" help\t\tShow help for given command.\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001231 exit(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +01001232}
1233
1234int main(int argc, char *argv[])
1235{
1236 int i, ret = 0;
1237
dp-arm5cd10ae2016-11-07 10:45:59 +00001238 while (1) {
1239 int c, opt_index = 0;
1240 static struct option opts[] = {
1241 { "verbose", no_argument, NULL, 'v' },
1242 { NULL, no_argument, NULL, 0 }
1243 };
1244
1245 /*
1246 * Set POSIX mode so getopt stops at the first non-option
1247 * which is the subcommand.
1248 */
1249 c = getopt_long(argc, argv, "+v", opts, &opt_index);
1250 if (c == -1)
1251 break;
dp-arm4972ec52016-05-25 16:20:20 +01001252
dp-arm5cd10ae2016-11-07 10:45:59 +00001253 switch (c) {
1254 case 'v':
1255 verbose = 1;
1256 break;
1257 default:
Masahiro Yamada48a24972016-10-26 13:24:26 +09001258 usage();
dp-arm5cd10ae2016-11-07 10:45:59 +00001259 }
dp-arm4972ec52016-05-25 16:20:20 +01001260 }
dp-arm5cd10ae2016-11-07 10:45:59 +00001261 argc -= optind;
1262 argv += optind;
1263 /* Reset optind for subsequent getopt processing. */
1264 optind = 0;
1265
1266 if (argc == 0)
1267 usage();
dp-arm4972ec52016-05-25 16:20:20 +01001268
dp-arm90d2f0e2016-11-14 15:54:32 +00001269 fill_image_descs();
dp-arm4972ec52016-05-25 16:20:20 +01001270 for (i = 0; i < NELEM(cmds); i++) {
1271 if (strcmp(cmds[i].name, argv[0]) == 0) {
1272 ret = cmds[i].handler(argc, argv);
1273 break;
1274 }
1275 }
1276 if (i == NELEM(cmds))
1277 usage();
dp-arm90d2f0e2016-11-14 15:54:32 +00001278 free_image_descs();
dp-arm4972ec52016-05-25 16:20:20 +01001279 return ret;
1280}