blob: 6c566ef00e41c11ae1ec03cc845b34502c90ae39 [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
Olivier Deprez9b9a5dc2023-08-31 11:46:54 +0200463#if !STATIC
dp-arm90d2f0e2016-11-14 15:54:32 +0000464static void md_print(const unsigned char *md, size_t len)
dp-arm12e893b2016-08-24 13:21:08 +0100465{
466 size_t i;
467
468 for (i = 0; i < len; i++)
469 printf("%02x", md[i]);
470}
Olivier Deprez9b9a5dc2023-08-31 11:46:54 +0200471#endif
dp-arm12e893b2016-08-24 13:21:08 +0100472
dp-arm4972ec52016-05-25 16:20:20 +0100473static int info_cmd(int argc, char *argv[])
474{
dp-armafa1efa2017-02-14 15:22:13 +0000475 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100476 fip_toc_header_t toc_header;
dp-arm4972ec52016-05-25 16:20:20 +0100477
478 if (argc != 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500479 info_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100480 argc--, argv++;
481
482 parse_fip(argv[0], &toc_header);
483
484 if (verbose) {
485 log_dbgx("toc_header[name]: 0x%llX",
486 (unsigned long long)toc_header.name);
487 log_dbgx("toc_header[serial_number]: 0x%llX",
488 (unsigned long long)toc_header.serial_number);
489 log_dbgx("toc_header[flags]: 0x%llX",
490 (unsigned long long)toc_header.flags);
491 }
492
dp-armafa1efa2017-02-14 15:22:13 +0000493 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
494 image_t *image = desc->image;
dp-arm715ef422016-08-30 14:18:58 +0100495
dp-armafa1efa2017-02-14 15:22:13 +0000496 if (image == NULL)
497 continue;
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900498 printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"--%s\"",
499 desc->name,
500 (unsigned long long)image->toc_e.offset_address,
501 (unsigned long long)image->toc_e.size,
Masahiro Yamadaeee39312017-01-15 23:20:00 +0900502 desc->cmdline_name);
Olivier Deprez9b9a5dc2023-08-31 11:46:54 +0200503
504 /*
505 * Omit this informative code portion for:
506 * Visual Studio missing SHA256.
507 * Statically linked builds.
508 */
509#if !defined(_MSC_VER) && !STATIC
dp-arm12e893b2016-08-24 13:21:08 +0100510 if (verbose) {
511 unsigned char md[SHA256_DIGEST_LENGTH];
512
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900513 SHA256(image->buffer, image->toc_e.size, md);
dp-arm12e893b2016-08-24 13:21:08 +0100514 printf(", sha256=");
515 md_print(md, sizeof(md));
516 }
Evan Lloyd04dc3442017-05-25 19:06:47 +0100517#endif
dp-arm12e893b2016-08-24 13:21:08 +0100518 putchar('\n');
dp-arm4972ec52016-05-25 16:20:20 +0100519 }
520
dp-arm4972ec52016-05-25 16:20:20 +0100521 return 0;
522}
523
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500524static void info_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +0100525{
526 printf("fiptool info FIP_FILENAME\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500527 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +0100528}
529
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900530static int pack_images(const char *filename, uint64_t toc_flags, unsigned long align)
dp-arm4972ec52016-05-25 16:20:20 +0100531{
532 FILE *fp;
dp-armafa1efa2017-02-14 15:22:13 +0000533 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100534 fip_toc_header_t *toc_header;
535 fip_toc_entry_t *toc_entry;
536 char *buf;
Roberto Vargas81935762017-12-19 11:56:57 +0000537 uint64_t entry_offset, buf_size, payload_size = 0, pad_size;
dp-armafa1efa2017-02-14 15:22:13 +0000538 size_t nr_images = 0;
539
540 for (desc = image_desc_head; desc != NULL; desc = desc->next)
541 if (desc->image != NULL)
542 nr_images++;
dp-arm4972ec52016-05-25 16:20:20 +0100543
544 buf_size = sizeof(fip_toc_header_t) +
545 sizeof(fip_toc_entry_t) * (nr_images + 1);
546 buf = calloc(1, buf_size);
547 if (buf == NULL)
548 log_err("calloc");
549
550 /* Build up header and ToC entries from the image table. */
551 toc_header = (fip_toc_header_t *)buf;
552 toc_header->name = TOC_HEADER_NAME;
553 toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
554 toc_header->flags = toc_flags;
555
556 toc_entry = (fip_toc_entry_t *)(toc_header + 1);
557
558 entry_offset = buf_size;
dp-armafa1efa2017-02-14 15:22:13 +0000559 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
560 image_t *image = desc->image;
561
Manish V Badarkhe0624d732021-12-18 11:26:25 +0000562 if (image == NULL || (image->toc_e.size == 0ULL))
dp-armafa1efa2017-02-14 15:22:13 +0000563 continue;
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900564 payload_size += image->toc_e.size;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900565 entry_offset = (entry_offset + align - 1) & ~(align - 1);
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900566 image->toc_e.offset_address = entry_offset;
567 *toc_entry++ = image->toc_e;
568 entry_offset += image->toc_e.size;
dp-arm4972ec52016-05-25 16:20:20 +0100569 }
570
Roberto Vargas81935762017-12-19 11:56:57 +0000571 /*
572 * Append a null uuid entry to mark the end of ToC entries.
573 * NOTE the offset address for the last toc_entry must match the fip
574 * size.
575 */
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900576 memset(toc_entry, 0, sizeof(*toc_entry));
Roberto Vargas81935762017-12-19 11:56:57 +0000577 toc_entry->offset_address = (entry_offset + align - 1) & ~(align - 1);
dp-arm4972ec52016-05-25 16:20:20 +0100578
579 /* Generate the FIP file. */
Evan Lloydb1939392017-01-13 14:13:09 +0000580 fp = fopen(filename, "wb");
dp-arm4972ec52016-05-25 16:20:20 +0100581 if (fp == NULL)
582 log_err("fopen %s", filename);
583
584 if (verbose)
585 log_dbgx("Metadata size: %zu bytes", buf_size);
586
Masahiro Yamada23f9b9e2017-01-27 03:54:02 +0900587 xfwrite(buf, buf_size, fp, filename);
dp-arm4972ec52016-05-25 16:20:20 +0100588
589 if (verbose)
590 log_dbgx("Payload size: %zu bytes", payload_size);
591
dp-armafa1efa2017-02-14 15:22:13 +0000592 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
593 image_t *image = desc->image;
594
595 if (image == NULL)
596 continue;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900597 if (fseek(fp, image->toc_e.offset_address, SEEK_SET))
598 log_errx("Failed to set file position");
599
Masahiro Yamada2fe0dad2017-01-27 03:56:58 +0900600 xfwrite(image->buffer, image->toc_e.size, fp, filename);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900601 }
dp-arm4972ec52016-05-25 16:20:20 +0100602
Roberto Vargas81935762017-12-19 11:56:57 +0000603 if (fseek(fp, entry_offset, SEEK_SET))
604 log_errx("Failed to set file position");
605
606 pad_size = toc_entry->offset_address - entry_offset;
607 while (pad_size--)
608 fputc(0x0, fp);
609
Andreas Färber860b5dc2018-01-27 16:46:59 +0100610 free(buf);
dp-arm4972ec52016-05-25 16:20:20 +0100611 fclose(fp);
612 return 0;
613}
614
615/*
616 * This function is shared between the create and update subcommands.
617 * The difference between the two subcommands is that when the FIP file
618 * is created, the parsing of an existing FIP is skipped. This results
619 * in update_fip() creating the new FIP file from scratch because the
620 * internal image table is not populated.
621 */
622static void update_fip(void)
623{
dp-arm90d2f0e2016-11-14 15:54:32 +0000624 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100625
626 /* Add or replace images in the FIP file. */
dp-arm90d2f0e2016-11-14 15:54:32 +0000627 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
dp-armafa1efa2017-02-14 15:22:13 +0000628 image_t *image;
dp-arm516dfcb2016-11-03 13:59:26 +0000629
dp-arm90d2f0e2016-11-14 15:54:32 +0000630 if (desc->action != DO_PACK)
dp-arm4972ec52016-05-25 16:20:20 +0100631 continue;
632
dp-armafa1efa2017-02-14 15:22:13 +0000633 image = read_image_from_file(&desc->uuid,
dp-arm90d2f0e2016-11-14 15:54:32 +0000634 desc->action_arg);
dp-armafa1efa2017-02-14 15:22:13 +0000635 if (desc->image != NULL) {
dp-arm90d2f0e2016-11-14 15:54:32 +0000636 if (verbose) {
dp-arm516dfcb2016-11-03 13:59:26 +0000637 log_dbgx("Replacing %s with %s",
dp-arm90d2f0e2016-11-14 15:54:32 +0000638 desc->cmdline_name,
639 desc->action_arg);
640 }
dp-armafa1efa2017-02-14 15:22:13 +0000641 free(desc->image);
642 desc->image = image;
dp-arm4972ec52016-05-25 16:20:20 +0100643 } else {
644 if (verbose)
645 log_dbgx("Adding image %s",
dp-arm90d2f0e2016-11-14 15:54:32 +0000646 desc->action_arg);
dp-armafa1efa2017-02-14 15:22:13 +0000647 desc->image = image;
dp-arm4972ec52016-05-25 16:20:20 +0100648 }
dp-arm4972ec52016-05-25 16:20:20 +0100649 }
650}
651
dp-arm90d2f0e2016-11-14 15:54:32 +0000652static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags)
dp-arm4972ec52016-05-25 16:20:20 +0100653{
654 unsigned long long flags;
655 char *endptr;
656
657 errno = 0;
658 flags = strtoull(arg, &endptr, 16);
659 if (*endptr != '\0' || flags > UINT16_MAX || errno != 0)
660 log_errx("Invalid platform ToC flags: %s", arg);
661 /* Platform ToC flags is a 16-bit field occupying bits [32-47]. */
662 *toc_flags |= flags << 32;
663}
664
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900665static int is_power_of_2(unsigned long x)
666{
667 return x && !(x & (x - 1));
668}
669
670static unsigned long get_image_align(char *arg)
671{
672 char *endptr;
673 unsigned long align;
674
675 errno = 0;
Andreas Färber242a7b72017-04-21 19:39:10 +0200676 align = strtoul(arg, &endptr, 0);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900677 if (*endptr != '\0' || !is_power_of_2(align) || errno != 0)
678 log_errx("Invalid alignment: %s", arg);
679
680 return align;
681}
682
dp-arm516dfcb2016-11-03 13:59:26 +0000683static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len)
684{
685 char *p;
686
687 for (p = strtok(arg, ","); p != NULL; p = strtok(NULL, ",")) {
688 if (strncmp(p, "uuid=", strlen("uuid=")) == 0) {
689 p += strlen("uuid=");
690 uuid_from_str(uuid, p);
691 } else if (strncmp(p, "file=", strlen("file=")) == 0) {
692 p += strlen("file=");
693 snprintf(filename, len, "%s", p);
694 }
695 }
696}
697
dp-arm4972ec52016-05-25 16:20:20 +0100698static int create_cmd(int argc, char *argv[])
699{
dp-arm90d2f0e2016-11-14 15:54:32 +0000700 struct option *opts = NULL;
701 size_t nr_opts = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100702 unsigned long long toc_flags = 0;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900703 unsigned long align = 1;
dp-arm4972ec52016-05-25 16:20:20 +0100704
705 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500706 create_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100707
dp-arm90d2f0e2016-11-14 15:54:32 +0000708 opts = fill_common_opts(opts, &nr_opts, required_argument);
709 opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
dp-arm4972ec52016-05-25 16:20:20 +0100710 OPT_PLAT_TOC_FLAGS);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900711 opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
dp-arm516dfcb2016-11-03 13:59:26 +0000712 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +0000713 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +0100714
715 while (1) {
dp-armfe92b892016-11-07 11:13:54 +0000716 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100717
dp-arm516dfcb2016-11-03 13:59:26 +0000718 c = getopt_long(argc, argv, "b:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +0100719 if (c == -1)
720 break;
721
722 switch (c) {
723 case OPT_TOC_ENTRY: {
dp-arm90d2f0e2016-11-14 15:54:32 +0000724 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100725
dp-arm90d2f0e2016-11-14 15:54:32 +0000726 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +0000727 set_image_desc_action(desc, DO_PACK, optarg);
dp-arm4972ec52016-05-25 16:20:20 +0100728 break;
729 }
730 case OPT_PLAT_TOC_FLAGS:
731 parse_plat_toc_flags(optarg, &toc_flags);
732 break;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900733 case OPT_ALIGN:
734 align = get_image_align(optarg);
735 break;
dp-arm516dfcb2016-11-03 13:59:26 +0000736 case 'b': {
737 char name[_UUID_STR_LEN + 1];
738 char filename[PATH_MAX] = { 0 };
Roberto Vargaseace8f12018-04-26 13:36:53 +0100739 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +0000740 image_desc_t *desc;
741
742 parse_blob_opt(optarg, &uuid,
743 filename, sizeof(filename));
744
745 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
746 filename[0] == '\0')
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500747 create_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +0000748
749 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +0000750 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +0000751 uuid_to_str(name, sizeof(name), &uuid);
752 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000753 add_image_desc(desc);
754 }
dp-armfb732312016-12-30 09:55:48 +0000755 set_image_desc_action(desc, DO_PACK, filename);
dp-arm516dfcb2016-11-03 13:59:26 +0000756 break;
757 }
dp-arm4972ec52016-05-25 16:20:20 +0100758 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500759 create_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100760 }
761 }
762 argc -= optind;
763 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +0000764 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +0100765
766 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500767 create_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +0100768
769 update_fip();
770
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900771 pack_images(argv[0], toc_flags, align);
dp-arm4972ec52016-05-25 16:20:20 +0100772 return 0;
773}
774
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500775static void create_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +0100776{
777 toc_entry_t *toc_entry = toc_entries;
778
Masahiro Yamada7abd0a22017-01-14 11:04:36 +0900779 printf("fiptool create [opts] FIP_FILENAME\n");
780 printf("\n");
781 printf("Options:\n");
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900782 printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +0900783 printf(" --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n");
784 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 +0900785 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +0100786 printf("Specific images are packed with the following options:\n");
787 for (; toc_entry->cmdline_name != NULL; toc_entry++)
788 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
789 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +0530790#ifdef PLAT_DEF_FIP_UUID
791 toc_entry = plat_def_toc_entries;
792 for (; toc_entry->cmdline_name != NULL; toc_entry++)
793 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
794 toc_entry->name);
795#endif
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500796 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +0100797}
798
799static int update_cmd(int argc, char *argv[])
800{
dp-arm90d2f0e2016-11-14 15:54:32 +0000801 struct option *opts = NULL;
802 size_t nr_opts = 0;
dp-arm516dfcb2016-11-03 13:59:26 +0000803 char outfile[PATH_MAX] = { 0 };
dp-arm4972ec52016-05-25 16:20:20 +0100804 fip_toc_header_t toc_header = { 0 };
805 unsigned long long toc_flags = 0;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900806 unsigned long align = 1;
dp-arm4972ec52016-05-25 16:20:20 +0100807 int pflag = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100808
809 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500810 update_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100811
dp-arm90d2f0e2016-11-14 15:54:32 +0000812 opts = fill_common_opts(opts, &nr_opts, required_argument);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900813 opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
dp-arm516dfcb2016-11-03 13:59:26 +0000814 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +0000815 opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
816 opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
dp-arm4972ec52016-05-25 16:20:20 +0100817 OPT_PLAT_TOC_FLAGS);
dp-arm90d2f0e2016-11-14 15:54:32 +0000818 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +0100819
820 while (1) {
dp-armfe92b892016-11-07 11:13:54 +0000821 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100822
dp-arm516dfcb2016-11-03 13:59:26 +0000823 c = getopt_long(argc, argv, "b:o:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +0100824 if (c == -1)
825 break;
826
827 switch (c) {
828 case OPT_TOC_ENTRY: {
dp-arm90d2f0e2016-11-14 15:54:32 +0000829 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100830
dp-arm90d2f0e2016-11-14 15:54:32 +0000831 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +0000832 set_image_desc_action(desc, DO_PACK, optarg);
dp-arm4972ec52016-05-25 16:20:20 +0100833 break;
834 }
dp-arm90d2f0e2016-11-14 15:54:32 +0000835 case OPT_PLAT_TOC_FLAGS:
dp-arm4972ec52016-05-25 16:20:20 +0100836 parse_plat_toc_flags(optarg, &toc_flags);
837 pflag = 1;
838 break;
dp-arm516dfcb2016-11-03 13:59:26 +0000839 case 'b': {
840 char name[_UUID_STR_LEN + 1];
841 char filename[PATH_MAX] = { 0 };
Roberto Vargaseace8f12018-04-26 13:36:53 +0100842 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +0000843 image_desc_t *desc;
844
845 parse_blob_opt(optarg, &uuid,
846 filename, sizeof(filename));
847
848 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
849 filename[0] == '\0')
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500850 update_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +0000851
852 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +0000853 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +0000854 uuid_to_str(name, sizeof(name), &uuid);
855 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000856 add_image_desc(desc);
857 }
dp-armfb732312016-12-30 09:55:48 +0000858 set_image_desc_action(desc, DO_PACK, filename);
dp-arm516dfcb2016-11-03 13:59:26 +0000859 break;
860 }
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900861 case OPT_ALIGN:
862 align = get_image_align(optarg);
863 break;
dp-arm4972ec52016-05-25 16:20:20 +0100864 case 'o':
865 snprintf(outfile, sizeof(outfile), "%s", optarg);
866 break;
867 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500868 update_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100869 }
870 }
871 argc -= optind;
872 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +0000873 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +0100874
875 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500876 update_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +0100877
878 if (outfile[0] == '\0')
879 snprintf(outfile, sizeof(outfile), "%s", argv[0]);
880
Masahiro Yamadaebb6e372016-12-25 12:41:41 +0900881 if (access(argv[0], F_OK) == 0)
dp-arm4972ec52016-05-25 16:20:20 +0100882 parse_fip(argv[0], &toc_header);
883
884 if (pflag)
885 toc_header.flags &= ~(0xffffULL << 32);
886 toc_flags = (toc_header.flags |= toc_flags);
887
888 update_fip();
889
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900890 pack_images(outfile, toc_flags, align);
dp-arm4972ec52016-05-25 16:20:20 +0100891 return 0;
892}
893
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500894static void update_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +0100895{
896 toc_entry_t *toc_entry = toc_entries;
897
Masahiro Yamada7abd0a22017-01-14 11:04:36 +0900898 printf("fiptool update [opts] FIP_FILENAME\n");
899 printf("\n");
900 printf("Options:\n");
Masahiro Yamada4d87eb42016-12-25 13:52:22 +0900901 printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +0900902 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 +0100903 printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +0900904 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 +0900905 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +0100906 printf("Specific images are packed with the following options:\n");
907 for (; toc_entry->cmdline_name != NULL; toc_entry++)
908 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
909 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +0530910#ifdef PLAT_DEF_FIP_UUID
911 toc_entry = plat_def_toc_entries;
912 for (; toc_entry->cmdline_name != NULL; toc_entry++)
913 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
914 toc_entry->name);
915#endif
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500916 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +0100917}
918
919static int unpack_cmd(int argc, char *argv[])
920{
dp-arm90d2f0e2016-11-14 15:54:32 +0000921 struct option *opts = NULL;
922 size_t nr_opts = 0;
dp-arm516dfcb2016-11-03 13:59:26 +0000923 char outdir[PATH_MAX] = { 0 };
dp-arm90d2f0e2016-11-14 15:54:32 +0000924 image_desc_t *desc;
dp-arm4972ec52016-05-25 16:20:20 +0100925 int fflag = 0;
926 int unpack_all = 1;
dp-arm4972ec52016-05-25 16:20:20 +0100927
928 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500929 unpack_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100930
dp-arm90d2f0e2016-11-14 15:54:32 +0000931 opts = fill_common_opts(opts, &nr_opts, required_argument);
dp-arm516dfcb2016-11-03 13:59:26 +0000932 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +0000933 opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
934 opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
935 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +0100936
937 while (1) {
dp-armfe92b892016-11-07 11:13:54 +0000938 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100939
dp-arm516dfcb2016-11-03 13:59:26 +0000940 c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +0100941 if (c == -1)
942 break;
943
944 switch (c) {
dp-arm90d2f0e2016-11-14 15:54:32 +0000945 case OPT_TOC_ENTRY: {
946 image_desc_t *desc;
947
948 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +0000949 set_image_desc_action(desc, DO_UNPACK, optarg);
dp-arm90d2f0e2016-11-14 15:54:32 +0000950 unpack_all = 0;
dp-arm4972ec52016-05-25 16:20:20 +0100951 break;
dp-arm90d2f0e2016-11-14 15:54:32 +0000952 }
dp-arm516dfcb2016-11-03 13:59:26 +0000953 case 'b': {
954 char name[_UUID_STR_LEN + 1];
955 char filename[PATH_MAX] = { 0 };
Roberto Vargaseace8f12018-04-26 13:36:53 +0100956 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +0000957 image_desc_t *desc;
958
959 parse_blob_opt(optarg, &uuid,
960 filename, sizeof(filename));
961
962 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
963 filename[0] == '\0')
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500964 unpack_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +0000965
966 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +0000967 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +0000968 uuid_to_str(name, sizeof(name), &uuid);
969 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +0000970 add_image_desc(desc);
971 }
dp-armfb732312016-12-30 09:55:48 +0000972 set_image_desc_action(desc, DO_UNPACK, filename);
dp-arm516dfcb2016-11-03 13:59:26 +0000973 unpack_all = 0;
974 break;
975 }
dp-arm4972ec52016-05-25 16:20:20 +0100976 case 'f':
977 fflag = 1;
978 break;
979 case 'o':
980 snprintf(outdir, sizeof(outdir), "%s", optarg);
981 break;
982 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500983 unpack_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +0100984 }
985 }
986 argc -= optind;
987 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +0000988 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +0100989
990 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -0500991 unpack_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +0100992
993 parse_fip(argv[0], NULL);
994
995 if (outdir[0] != '\0')
996 if (chdir(outdir) == -1)
997 log_err("chdir %s", outdir);
998
dp-arm4972ec52016-05-25 16:20:20 +0100999 /* Unpack all specified images. */
dp-arm90d2f0e2016-11-14 15:54:32 +00001000 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
dp-arm516dfcb2016-11-03 13:59:26 +00001001 char file[PATH_MAX];
dp-armafa1efa2017-02-14 15:22:13 +00001002 image_t *image = desc->image;
dp-arm715ef422016-08-30 14:18:58 +01001003
dp-arm90d2f0e2016-11-14 15:54:32 +00001004 if (!unpack_all && desc->action != DO_UNPACK)
dp-arm4972ec52016-05-25 16:20:20 +01001005 continue;
1006
1007 /* Build filename. */
dp-arm90d2f0e2016-11-14 15:54:32 +00001008 if (desc->action_arg == NULL)
dp-arm4972ec52016-05-25 16:20:20 +01001009 snprintf(file, sizeof(file), "%s.bin",
dp-arm90d2f0e2016-11-14 15:54:32 +00001010 desc->cmdline_name);
dp-arm4972ec52016-05-25 16:20:20 +01001011 else
1012 snprintf(file, sizeof(file), "%s",
dp-arm90d2f0e2016-11-14 15:54:32 +00001013 desc->action_arg);
dp-arm4972ec52016-05-25 16:20:20 +01001014
dp-arm715ef422016-08-30 14:18:58 +01001015 if (image == NULL) {
1016 if (!unpack_all)
dp-arm516dfcb2016-11-03 13:59:26 +00001017 log_warnx("%s does not exist in %s",
dp-arm715ef422016-08-30 14:18:58 +01001018 file, argv[0]);
dp-arm4972ec52016-05-25 16:20:20 +01001019 continue;
1020 }
1021
1022 if (access(file, F_OK) != 0 || fflag) {
1023 if (verbose)
1024 log_dbgx("Unpacking %s", file);
dp-arm715ef422016-08-30 14:18:58 +01001025 write_image_to_file(image, file);
dp-arm4972ec52016-05-25 16:20:20 +01001026 } else {
1027 log_warnx("File %s already exists, use --force to overwrite it",
1028 file);
1029 }
dp-arm4972ec52016-05-25 16:20:20 +01001030 }
1031
dp-arm4972ec52016-05-25 16:20:20 +01001032 return 0;
1033}
1034
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001035static void unpack_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +01001036{
1037 toc_entry_t *toc_entry = toc_entries;
1038
Masahiro Yamada7abd0a22017-01-14 11:04:36 +09001039 printf("fiptool unpack [opts] FIP_FILENAME\n");
1040 printf("\n");
1041 printf("Options:\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +09001042 printf(" --blob uuid=...,file=...\tUnpack an image with the given UUID to file.\n");
1043 printf(" --force\t\t\tIf the output file already exists, use --force to overwrite it.\n");
dp-arm516dfcb2016-11-03 13:59:26 +00001044 printf(" --out path\t\t\tSet the output directory path.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +09001045 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001046 printf("Specific images are unpacked with the following options:\n");
1047 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1048 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
1049 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +05301050#ifdef PLAT_DEF_FIP_UUID
1051 toc_entry = plat_def_toc_entries;
1052 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1053 printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
1054 toc_entry->name);
1055#endif
Masahiro Yamada1b900152017-02-02 16:34:14 +09001056 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001057 printf("If no options are provided, all images will be unpacked.\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001058 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +01001059}
1060
1061static int remove_cmd(int argc, char *argv[])
1062{
dp-arm90d2f0e2016-11-14 15:54:32 +00001063 struct option *opts = NULL;
1064 size_t nr_opts = 0;
dp-arm516dfcb2016-11-03 13:59:26 +00001065 char outfile[PATH_MAX] = { 0 };
dp-arm4972ec52016-05-25 16:20:20 +01001066 fip_toc_header_t toc_header;
dp-arm90d2f0e2016-11-14 15:54:32 +00001067 image_desc_t *desc;
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001068 unsigned long align = 1;
dp-arm4972ec52016-05-25 16:20:20 +01001069 int fflag = 0;
dp-arm4972ec52016-05-25 16:20:20 +01001070
1071 if (argc < 2)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001072 remove_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +01001073
dp-arm90d2f0e2016-11-14 15:54:32 +00001074 opts = fill_common_opts(opts, &nr_opts, no_argument);
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001075 opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
dp-arm516dfcb2016-11-03 13:59:26 +00001076 opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
dp-arm90d2f0e2016-11-14 15:54:32 +00001077 opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
1078 opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
1079 opts = add_opt(opts, &nr_opts, NULL, 0, 0);
dp-arm4972ec52016-05-25 16:20:20 +01001080
1081 while (1) {
dp-armfe92b892016-11-07 11:13:54 +00001082 int c, opt_index = 0;
dp-arm4972ec52016-05-25 16:20:20 +01001083
dp-arm516dfcb2016-11-03 13:59:26 +00001084 c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
dp-arm4972ec52016-05-25 16:20:20 +01001085 if (c == -1)
1086 break;
1087
1088 switch (c) {
dp-arm90d2f0e2016-11-14 15:54:32 +00001089 case OPT_TOC_ENTRY: {
1090 image_desc_t *desc;
1091
1092 desc = lookup_image_desc_from_opt(opts[opt_index].name);
dp-armfb732312016-12-30 09:55:48 +00001093 set_image_desc_action(desc, DO_REMOVE, NULL);
dp-arm4972ec52016-05-25 16:20:20 +01001094 break;
dp-arm90d2f0e2016-11-14 15:54:32 +00001095 }
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001096 case OPT_ALIGN:
1097 align = get_image_align(optarg);
1098 break;
dp-arm516dfcb2016-11-03 13:59:26 +00001099 case 'b': {
1100 char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
Roberto Vargaseace8f12018-04-26 13:36:53 +01001101 uuid_t uuid = uuid_null;
dp-arm516dfcb2016-11-03 13:59:26 +00001102 image_desc_t *desc;
1103
1104 parse_blob_opt(optarg, &uuid,
1105 filename, sizeof(filename));
1106
1107 if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001108 remove_usage(EXIT_FAILURE);
dp-arm516dfcb2016-11-03 13:59:26 +00001109
1110 desc = lookup_image_desc_from_uuid(&uuid);
dp-armfb732312016-12-30 09:55:48 +00001111 if (desc == NULL) {
dp-arm516dfcb2016-11-03 13:59:26 +00001112 uuid_to_str(name, sizeof(name), &uuid);
1113 desc = new_image_desc(&uuid, name, "blob");
dp-arm516dfcb2016-11-03 13:59:26 +00001114 add_image_desc(desc);
1115 }
dp-armfb732312016-12-30 09:55:48 +00001116 set_image_desc_action(desc, DO_REMOVE, NULL);
dp-arm516dfcb2016-11-03 13:59:26 +00001117 break;
1118 }
dp-arm4972ec52016-05-25 16:20:20 +01001119 case 'f':
1120 fflag = 1;
1121 break;
1122 case 'o':
1123 snprintf(outfile, sizeof(outfile), "%s", optarg);
1124 break;
1125 default:
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001126 remove_usage(EXIT_FAILURE);
dp-arm4972ec52016-05-25 16:20:20 +01001127 }
1128 }
1129 argc -= optind;
1130 argv += optind;
dp-arm90d2f0e2016-11-14 15:54:32 +00001131 free(opts);
dp-arm4972ec52016-05-25 16:20:20 +01001132
1133 if (argc == 0)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001134 remove_usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +01001135
1136 if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag)
1137 log_errx("File %s already exists, use --force to overwrite it",
1138 outfile);
1139
1140 if (outfile[0] == '\0')
1141 snprintf(outfile, sizeof(outfile), "%s", argv[0]);
1142
1143 parse_fip(argv[0], &toc_header);
1144
dp-arm90d2f0e2016-11-14 15:54:32 +00001145 for (desc = image_desc_head; desc != NULL; desc = desc->next) {
dp-arm90d2f0e2016-11-14 15:54:32 +00001146 if (desc->action != DO_REMOVE)
dp-arm4972ec52016-05-25 16:20:20 +01001147 continue;
dp-arm516dfcb2016-11-03 13:59:26 +00001148
dp-armafa1efa2017-02-14 15:22:13 +00001149 if (desc->image != NULL) {
dp-arm4972ec52016-05-25 16:20:20 +01001150 if (verbose)
dp-arm516dfcb2016-11-03 13:59:26 +00001151 log_dbgx("Removing %s",
dp-arm90d2f0e2016-11-14 15:54:32 +00001152 desc->cmdline_name);
dp-armafa1efa2017-02-14 15:22:13 +00001153 free(desc->image);
1154 desc->image = NULL;
dp-arm4972ec52016-05-25 16:20:20 +01001155 } else {
dp-arm516dfcb2016-11-03 13:59:26 +00001156 log_warnx("%s does not exist in %s",
dp-arm90d2f0e2016-11-14 15:54:32 +00001157 desc->cmdline_name, argv[0]);
dp-arm4972ec52016-05-25 16:20:20 +01001158 }
1159 }
1160
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001161 pack_images(outfile, toc_header.flags, align);
dp-arm4972ec52016-05-25 16:20:20 +01001162 return 0;
1163}
1164
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001165static void remove_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +01001166{
1167 toc_entry_t *toc_entry = toc_entries;
1168
Masahiro Yamada7abd0a22017-01-14 11:04:36 +09001169 printf("fiptool remove [opts] FIP_FILENAME\n");
1170 printf("\n");
1171 printf("Options:\n");
Masahiro Yamada4d87eb42016-12-25 13:52:22 +09001172 printf(" --align <value>\tEach image is aligned to <value> (default: 1).\n");
dp-arm516dfcb2016-11-03 13:59:26 +00001173 printf(" --blob uuid=...\tRemove an image with the given UUID.\n");
Masahiro Yamada1eee6a82017-02-02 16:37:37 +09001174 printf(" --force\t\tIf the output FIP file already exists, use --force to overwrite it.\n");
dp-arm4972ec52016-05-25 16:20:20 +01001175 printf(" --out FIP_FILENAME\tSet an alternative output FIP file.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +09001176 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001177 printf("Specific images are removed with the following options:\n");
1178 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1179 printf(" --%-16s\t%s\n", toc_entry->cmdline_name,
1180 toc_entry->name);
Pankaj Guptae4aa1bd2020-12-09 14:02:38 +05301181#ifdef PLAT_DEF_FIP_UUID
1182 toc_entry = plat_def_toc_entries;
1183 for (; toc_entry->cmdline_name != NULL; toc_entry++)
1184 printf(" --%-16s\t%s\n", toc_entry->cmdline_name,
1185 toc_entry->name);
1186#endif
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001187 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +01001188}
1189
1190static int version_cmd(int argc, char *argv[])
1191{
1192#ifdef VERSION
1193 puts(VERSION);
1194#else
1195 /* If built from fiptool directory, VERSION is not set. */
1196 puts("Unknown version");
1197#endif
1198 return 0;
1199}
1200
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001201static void version_usage(int exit_status)
dp-arm4972ec52016-05-25 16:20:20 +01001202{
1203 printf("fiptool version\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001204 exit(exit_status);
dp-arm4972ec52016-05-25 16:20:20 +01001205}
1206
1207static int help_cmd(int argc, char *argv[])
1208{
1209 int i;
1210
1211 if (argc < 2)
1212 usage();
1213 argc--, argv++;
1214
1215 for (i = 0; i < NELEM(cmds); i++) {
1216 if (strcmp(cmds[i].name, argv[0]) == 0 &&
dp-arm29f1b5c2016-09-15 09:58:50 +01001217 cmds[i].usage != NULL)
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001218 cmds[i].usage(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +01001219 }
1220 if (i == NELEM(cmds))
1221 printf("No help for subcommand '%s'\n", argv[0]);
1222 return 0;
1223}
1224
1225static void usage(void)
1226{
Masahiro Yamada252c3362017-01-13 02:13:06 +09001227 printf("usage: fiptool [--verbose] <command> [<args>]\n");
dp-arm4972ec52016-05-25 16:20:20 +01001228 printf("Global options supported:\n");
1229 printf(" --verbose\tEnable verbose output for all commands.\n");
Masahiro Yamada1b900152017-02-02 16:34:14 +09001230 printf("\n");
dp-arm4972ec52016-05-25 16:20:20 +01001231 printf("Commands supported:\n");
1232 printf(" info\t\tList images contained in FIP.\n");
1233 printf(" create\tCreate a new FIP with the given images.\n");
1234 printf(" update\tUpdate an existing FIP with the given images.\n");
1235 printf(" unpack\tUnpack images from FIP.\n");
1236 printf(" remove\tRemove images from FIP.\n");
1237 printf(" version\tShow fiptool version.\n");
1238 printf(" help\t\tShow help for given command.\n");
Leonardo Sandovalfc6d3852020-06-29 18:09:24 -05001239 exit(EXIT_SUCCESS);
dp-arm4972ec52016-05-25 16:20:20 +01001240}
1241
1242int main(int argc, char *argv[])
1243{
1244 int i, ret = 0;
1245
dp-arm5cd10ae2016-11-07 10:45:59 +00001246 while (1) {
1247 int c, opt_index = 0;
1248 static struct option opts[] = {
1249 { "verbose", no_argument, NULL, 'v' },
1250 { NULL, no_argument, NULL, 0 }
1251 };
1252
1253 /*
1254 * Set POSIX mode so getopt stops at the first non-option
1255 * which is the subcommand.
1256 */
1257 c = getopt_long(argc, argv, "+v", opts, &opt_index);
1258 if (c == -1)
1259 break;
dp-arm4972ec52016-05-25 16:20:20 +01001260
dp-arm5cd10ae2016-11-07 10:45:59 +00001261 switch (c) {
1262 case 'v':
1263 verbose = 1;
1264 break;
1265 default:
Masahiro Yamada48a24972016-10-26 13:24:26 +09001266 usage();
dp-arm5cd10ae2016-11-07 10:45:59 +00001267 }
dp-arm4972ec52016-05-25 16:20:20 +01001268 }
dp-arm5cd10ae2016-11-07 10:45:59 +00001269 argc -= optind;
1270 argv += optind;
1271 /* Reset optind for subsequent getopt processing. */
1272 optind = 0;
1273
1274 if (argc == 0)
1275 usage();
dp-arm4972ec52016-05-25 16:20:20 +01001276
dp-arm90d2f0e2016-11-14 15:54:32 +00001277 fill_image_descs();
dp-arm4972ec52016-05-25 16:20:20 +01001278 for (i = 0; i < NELEM(cmds); i++) {
1279 if (strcmp(cmds[i].name, argv[0]) == 0) {
1280 ret = cmds[i].handler(argc, argv);
1281 break;
1282 }
1283 }
1284 if (i == NELEM(cmds))
1285 usage();
dp-arm90d2f0e2016-11-14 15:54:32 +00001286 free_image_descs();
dp-arm4972ec52016-05-25 16:20:20 +01001287 return ret;
1288}