1819281eeSdp-arm /*
2*ccbfd01dSManish V Badarkhe * Copyright (c) 2016-2024, Arm Limited and Contributors. All rights reserved.
3819281eeSdp-arm *
482cb2c1aSdp-arm * SPDX-License-Identifier: BSD-3-Clause
5819281eeSdp-arm */
6819281eeSdp-arm
7*ccbfd01dSManish V Badarkhe #ifdef __linux__
806e69f7cSAntonio Borneo #include <sys/mount.h>
906e69f7cSAntonio Borneo #endif
10*ccbfd01dSManish V Badarkhe
11819281eeSdp-arm #include <sys/types.h>
12819281eeSdp-arm #include <sys/stat.h>
13819281eeSdp-arm
14819281eeSdp-arm #include <assert.h>
15819281eeSdp-arm #include <errno.h>
16819281eeSdp-arm #include <limits.h>
17819281eeSdp-arm #include <stdarg.h>
18819281eeSdp-arm #include <stdint.h>
19819281eeSdp-arm #include <stdio.h>
20819281eeSdp-arm #include <stdlib.h>
21819281eeSdp-arm #include <string.h>
222a6c1a8fSMasahiro Yamada
23819281eeSdp-arm #include "fiptool.h"
24819281eeSdp-arm #include "tbbr_config.h"
25819281eeSdp-arm
26819281eeSdp-arm #define OPT_TOC_ENTRY 0
27819281eeSdp-arm #define OPT_PLAT_TOC_FLAGS 1
281c75d5dfSMasahiro Yamada #define OPT_ALIGN 2
29819281eeSdp-arm
30819281eeSdp-arm static int info_cmd(int argc, char *argv[]);
314e500525SLeonardo Sandoval static void info_usage(int);
32819281eeSdp-arm static int create_cmd(int argc, char *argv[]);
334e500525SLeonardo Sandoval static void create_usage(int);
34819281eeSdp-arm static int update_cmd(int argc, char *argv[]);
354e500525SLeonardo Sandoval static void update_usage(int);
36819281eeSdp-arm static int unpack_cmd(int argc, char *argv[]);
374e500525SLeonardo Sandoval static void unpack_usage(int);
38819281eeSdp-arm static int remove_cmd(int argc, char *argv[]);
394e500525SLeonardo Sandoval static void remove_usage(int);
40819281eeSdp-arm static int version_cmd(int argc, char *argv[]);
414e500525SLeonardo Sandoval static void version_usage(int);
42819281eeSdp-arm static int help_cmd(int argc, char *argv[]);
43819281eeSdp-arm static void usage(void);
44819281eeSdp-arm
45819281eeSdp-arm /* Available subcommands. */
46819281eeSdp-arm static cmd_t cmds[] = {
47819281eeSdp-arm { .name = "info", .handler = info_cmd, .usage = info_usage },
48819281eeSdp-arm { .name = "create", .handler = create_cmd, .usage = create_usage },
49819281eeSdp-arm { .name = "update", .handler = update_cmd, .usage = update_usage },
50819281eeSdp-arm { .name = "unpack", .handler = unpack_cmd, .usage = unpack_usage },
51819281eeSdp-arm { .name = "remove", .handler = remove_cmd, .usage = remove_usage },
52819281eeSdp-arm { .name = "version", .handler = version_cmd, .usage = version_usage },
53819281eeSdp-arm { .name = "help", .handler = help_cmd, .usage = NULL },
54819281eeSdp-arm };
55819281eeSdp-arm
56e0f083a0Sdp-arm static image_desc_t *image_desc_head;
57e0f083a0Sdp-arm static size_t nr_image_descs;
5803364865SRoberto Vargas static const uuid_t uuid_null;
59819281eeSdp-arm static int verbose;
60819281eeSdp-arm
vlog(int prio,const char * msg,va_list ap)6160b499feSdp-arm static void vlog(int prio, const char *msg, va_list ap)
62819281eeSdp-arm {
63819281eeSdp-arm char *prefix[] = { "DEBUG", "WARN", "ERROR" };
64819281eeSdp-arm
65819281eeSdp-arm fprintf(stderr, "%s: ", prefix[prio]);
66819281eeSdp-arm vfprintf(stderr, msg, ap);
67819281eeSdp-arm fputc('\n', stderr);
68819281eeSdp-arm }
69819281eeSdp-arm
log_dbgx(const char * msg,...)7060b499feSdp-arm static void log_dbgx(const char *msg, ...)
71819281eeSdp-arm {
72819281eeSdp-arm va_list ap;
73819281eeSdp-arm
74819281eeSdp-arm va_start(ap, msg);
75819281eeSdp-arm vlog(LOG_DBG, msg, ap);
76819281eeSdp-arm va_end(ap);
77819281eeSdp-arm }
78819281eeSdp-arm
log_warnx(const char * msg,...)7960b499feSdp-arm static void log_warnx(const char *msg, ...)
80819281eeSdp-arm {
81819281eeSdp-arm va_list ap;
82819281eeSdp-arm
83819281eeSdp-arm va_start(ap, msg);
84819281eeSdp-arm vlog(LOG_WARN, msg, ap);
85819281eeSdp-arm va_end(ap);
86819281eeSdp-arm }
87819281eeSdp-arm
log_err(const char * msg,...)8860b499feSdp-arm static void log_err(const char *msg, ...)
89819281eeSdp-arm {
90819281eeSdp-arm char buf[512];
91819281eeSdp-arm va_list ap;
92819281eeSdp-arm
93819281eeSdp-arm va_start(ap, msg);
94819281eeSdp-arm snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno));
95819281eeSdp-arm vlog(LOG_ERR, buf, ap);
96819281eeSdp-arm va_end(ap);
97819281eeSdp-arm exit(1);
98819281eeSdp-arm }
99819281eeSdp-arm
log_errx(const char * msg,...)10060b499feSdp-arm static void log_errx(const char *msg, ...)
101819281eeSdp-arm {
102819281eeSdp-arm va_list ap;
103819281eeSdp-arm
104819281eeSdp-arm va_start(ap, msg);
105819281eeSdp-arm vlog(LOG_ERR, msg, ap);
106819281eeSdp-arm va_end(ap);
107819281eeSdp-arm exit(1);
108819281eeSdp-arm }
109819281eeSdp-arm
xstrdup(const char * s,const char * msg)110a22f6285Sdp-arm static char *xstrdup(const char *s, const char *msg)
111a22f6285Sdp-arm {
112a22f6285Sdp-arm char *d;
113a22f6285Sdp-arm
114a22f6285Sdp-arm d = strdup(s);
115a22f6285Sdp-arm if (d == NULL)
1169fc9ff1fSdp-arm log_errx("strdup: %s", msg);
117a22f6285Sdp-arm return d;
118a22f6285Sdp-arm }
119a22f6285Sdp-arm
xmalloc(size_t size,const char * msg)120a22f6285Sdp-arm static void *xmalloc(size_t size, const char *msg)
121a22f6285Sdp-arm {
122a22f6285Sdp-arm void *d;
123a22f6285Sdp-arm
124a22f6285Sdp-arm d = malloc(size);
125a22f6285Sdp-arm if (d == NULL)
1269fc9ff1fSdp-arm log_errx("malloc: %s", msg);
127a22f6285Sdp-arm return d;
128a22f6285Sdp-arm }
129a22f6285Sdp-arm
xzalloc(size_t size,const char * msg)130696ccba6SMasahiro Yamada static void *xzalloc(size_t size, const char *msg)
131696ccba6SMasahiro Yamada {
132696ccba6SMasahiro Yamada return memset(xmalloc(size, msg), 0, size);
133696ccba6SMasahiro Yamada }
134696ccba6SMasahiro Yamada
xfwrite(void * buf,size_t size,FILE * fp,const char * filename)135a1da83f5SMasahiro Yamada static void xfwrite(void *buf, size_t size, FILE *fp, const char *filename)
136a1da83f5SMasahiro Yamada {
137a1da83f5SMasahiro Yamada if (fwrite(buf, 1, size, fp) != size)
138a1da83f5SMasahiro Yamada log_errx("Failed to write %s", filename);
139a1da83f5SMasahiro Yamada }
140a1da83f5SMasahiro Yamada
new_image_desc(const uuid_t * uuid,const char * name,const char * cmdline_name)141e0f083a0Sdp-arm static image_desc_t *new_image_desc(const uuid_t *uuid,
142e0f083a0Sdp-arm const char *name, const char *cmdline_name)
143e0f083a0Sdp-arm {
144e0f083a0Sdp-arm image_desc_t *desc;
145e0f083a0Sdp-arm
146696ccba6SMasahiro Yamada desc = xzalloc(sizeof(*desc),
147e0f083a0Sdp-arm "failed to allocate memory for image descriptor");
148e0f083a0Sdp-arm memcpy(&desc->uuid, uuid, sizeof(uuid_t));
149e0f083a0Sdp-arm desc->name = xstrdup(name,
150e0f083a0Sdp-arm "failed to allocate memory for image name");
151e0f083a0Sdp-arm desc->cmdline_name = xstrdup(cmdline_name,
152e0f083a0Sdp-arm "failed to allocate memory for image command line name");
153e0f083a0Sdp-arm desc->action = DO_UNSPEC;
154e0f083a0Sdp-arm return desc;
155e0f083a0Sdp-arm }
156e0f083a0Sdp-arm
set_image_desc_action(image_desc_t * desc,int action,const char * arg)157d02fcebeSdp-arm static void set_image_desc_action(image_desc_t *desc, int action,
158d02fcebeSdp-arm const char *arg)
159d02fcebeSdp-arm {
160d02fcebeSdp-arm assert(desc != NULL);
161d02fcebeSdp-arm
16296851114SEvan Lloyd if (desc->action_arg != (char *)DO_UNSPEC)
163d02fcebeSdp-arm free(desc->action_arg);
164d02fcebeSdp-arm desc->action = action;
165d02fcebeSdp-arm desc->action_arg = NULL;
166d02fcebeSdp-arm if (arg != NULL)
167d02fcebeSdp-arm desc->action_arg = xstrdup(arg,
168d02fcebeSdp-arm "failed to allocate memory for argument");
169d02fcebeSdp-arm }
170d02fcebeSdp-arm
free_image_desc(image_desc_t * desc)171e0f083a0Sdp-arm static void free_image_desc(image_desc_t *desc)
172e0f083a0Sdp-arm {
173e0f083a0Sdp-arm free(desc->name);
174e0f083a0Sdp-arm free(desc->cmdline_name);
175e0f083a0Sdp-arm free(desc->action_arg);
1768d283231SJonathan Wright if (desc->image) {
1778d283231SJonathan Wright free(desc->image->buffer);
178b9589fe5Sdp-arm free(desc->image);
1798d283231SJonathan Wright }
180e0f083a0Sdp-arm free(desc);
181e0f083a0Sdp-arm }
182e0f083a0Sdp-arm
add_image_desc(image_desc_t * desc)183e0f083a0Sdp-arm static void add_image_desc(image_desc_t *desc)
184e0f083a0Sdp-arm {
18511c0a4ffSMasahiro Yamada image_desc_t **p = &image_desc_head;
18611c0a4ffSMasahiro Yamada
18711c0a4ffSMasahiro Yamada while (*p)
18811c0a4ffSMasahiro Yamada p = &(*p)->next;
18911c0a4ffSMasahiro Yamada
190e9e0d287SMasahiro Yamada assert(*p == NULL);
19111c0a4ffSMasahiro Yamada *p = desc;
192e0f083a0Sdp-arm nr_image_descs++;
193e0f083a0Sdp-arm }
194e0f083a0Sdp-arm
free_image_descs(void)195e0f083a0Sdp-arm static void free_image_descs(void)
196e0f083a0Sdp-arm {
197e0f083a0Sdp-arm image_desc_t *desc = image_desc_head, *tmp;
198e0f083a0Sdp-arm
199e0f083a0Sdp-arm while (desc != NULL) {
200e0f083a0Sdp-arm tmp = desc->next;
201e0f083a0Sdp-arm free_image_desc(desc);
202e0f083a0Sdp-arm desc = tmp;
203e0f083a0Sdp-arm nr_image_descs--;
204e0f083a0Sdp-arm }
205e0f083a0Sdp-arm assert(nr_image_descs == 0);
206e0f083a0Sdp-arm }
207e0f083a0Sdp-arm
fill_image_descs(void)208e0f083a0Sdp-arm static void fill_image_descs(void)
209e0f083a0Sdp-arm {
210e0f083a0Sdp-arm toc_entry_t *toc_entry;
211e0f083a0Sdp-arm
212e0f083a0Sdp-arm for (toc_entry = toc_entries;
213e0f083a0Sdp-arm toc_entry->cmdline_name != NULL;
214e0f083a0Sdp-arm toc_entry++) {
215e0f083a0Sdp-arm image_desc_t *desc;
216e0f083a0Sdp-arm
217e0f083a0Sdp-arm desc = new_image_desc(&toc_entry->uuid,
218e0f083a0Sdp-arm toc_entry->name,
219e0f083a0Sdp-arm toc_entry->cmdline_name);
220e0f083a0Sdp-arm add_image_desc(desc);
221e0f083a0Sdp-arm }
2223527d6d2SPankaj Gupta #ifdef PLAT_DEF_FIP_UUID
2233527d6d2SPankaj Gupta for (toc_entry = plat_def_toc_entries;
2243527d6d2SPankaj Gupta toc_entry->cmdline_name != NULL;
2253527d6d2SPankaj Gupta toc_entry++) {
2263527d6d2SPankaj Gupta image_desc_t *desc;
2273527d6d2SPankaj Gupta
2283527d6d2SPankaj Gupta desc = new_image_desc(&toc_entry->uuid,
2293527d6d2SPankaj Gupta toc_entry->name,
2303527d6d2SPankaj Gupta toc_entry->cmdline_name);
2313527d6d2SPankaj Gupta add_image_desc(desc);
2323527d6d2SPankaj Gupta }
2333527d6d2SPankaj Gupta #endif
234e0f083a0Sdp-arm }
235e0f083a0Sdp-arm
lookup_image_desc_from_uuid(const uuid_t * uuid)236e0f083a0Sdp-arm static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid)
237819281eeSdp-arm {
238e0f083a0Sdp-arm image_desc_t *desc;
239819281eeSdp-arm
240e0f083a0Sdp-arm for (desc = image_desc_head; desc != NULL; desc = desc->next)
241e0f083a0Sdp-arm if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
242e0f083a0Sdp-arm return desc;
243819281eeSdp-arm return NULL;
244819281eeSdp-arm }
245819281eeSdp-arm
lookup_image_desc_from_opt(const char * opt)246e0f083a0Sdp-arm static image_desc_t *lookup_image_desc_from_opt(const char *opt)
247e0f083a0Sdp-arm {
248e0f083a0Sdp-arm image_desc_t *desc;
249e0f083a0Sdp-arm
250e0f083a0Sdp-arm for (desc = image_desc_head; desc != NULL; desc = desc->next)
251e0f083a0Sdp-arm if (strcmp(desc->cmdline_name, opt) == 0)
252e0f083a0Sdp-arm return desc;
253e0f083a0Sdp-arm return NULL;
254e0f083a0Sdp-arm }
255e0f083a0Sdp-arm
uuid_to_str(char * s,size_t len,const uuid_t * u)256fcab6bbeSdp-arm static void uuid_to_str(char *s, size_t len, const uuid_t *u)
257fcab6bbeSdp-arm {
258fcab6bbeSdp-arm assert(len >= (_UUID_STR_LEN + 1));
259fcab6bbeSdp-arm
26003364865SRoberto Vargas snprintf(s, len,
26103364865SRoberto Vargas "%02X%02X%02X%02X-%02X%02X-%02X%02X-%04X-%04X%04X%04X",
26203364865SRoberto Vargas u->time_low[0], u->time_low[1], u->time_low[2], u->time_low[3],
26303364865SRoberto Vargas u->time_mid[0], u->time_mid[1],
26403364865SRoberto Vargas u->time_hi_and_version[0], u->time_hi_and_version[1],
26503364865SRoberto Vargas (u->clock_seq_hi_and_reserved << 8) | u->clock_seq_low,
26603364865SRoberto Vargas (u->node[0] << 8) | u->node[1],
26703364865SRoberto Vargas (u->node[2] << 8) | u->node[3],
26803364865SRoberto Vargas (u->node[4] << 8) | u->node[5]);
269fcab6bbeSdp-arm }
270fcab6bbeSdp-arm
uuid_from_str(uuid_t * u,const char * s)271fcab6bbeSdp-arm static void uuid_from_str(uuid_t *u, const char *s)
272fcab6bbeSdp-arm {
273fcab6bbeSdp-arm int n;
274fcab6bbeSdp-arm
275fcab6bbeSdp-arm if (s == NULL)
276fcab6bbeSdp-arm log_errx("UUID cannot be NULL");
277fcab6bbeSdp-arm if (strlen(s) != _UUID_STR_LEN)
278fcab6bbeSdp-arm log_errx("Invalid UUID: %s", s);
279fcab6bbeSdp-arm
280fcab6bbeSdp-arm n = sscanf(s,
28103364865SRoberto Vargas "%2hhx%2hhx%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
28203364865SRoberto Vargas &u->time_low[0], &u->time_low[1], &u->time_low[2], &u->time_low[3],
28303364865SRoberto Vargas &u->time_mid[0], &u->time_mid[1],
28403364865SRoberto Vargas &u->time_hi_and_version[0], &u->time_hi_and_version[1],
28503364865SRoberto Vargas &u->clock_seq_hi_and_reserved, &u->clock_seq_low,
28603364865SRoberto Vargas &u->node[0], &u->node[1],
28703364865SRoberto Vargas &u->node[2], &u->node[3],
28803364865SRoberto Vargas &u->node[4], &u->node[5]);
289fcab6bbeSdp-arm /*
290e56b8dc8SAndre Przywara * Given the format specifier above, we expect 16 items to be scanned
291fcab6bbeSdp-arm * for a properly formatted UUID.
292fcab6bbeSdp-arm */
293e56b8dc8SAndre Przywara if (n != 16)
294fcab6bbeSdp-arm log_errx("Invalid UUID: %s", s);
295fcab6bbeSdp-arm }
296fcab6bbeSdp-arm
parse_fip(const char * filename,fip_toc_header_t * toc_header_out)29760b499feSdp-arm static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
298819281eeSdp-arm {
29996851114SEvan Lloyd struct BLD_PLAT_STAT st;
300819281eeSdp-arm FILE *fp;
301819281eeSdp-arm char *buf, *bufend;
302819281eeSdp-arm fip_toc_header_t *toc_header;
303819281eeSdp-arm fip_toc_entry_t *toc_entry;
304819281eeSdp-arm int terminated = 0;
30506e69f7cSAntonio Borneo size_t st_size;
306819281eeSdp-arm
30755745deaSEvan Lloyd fp = fopen(filename, "rb");
308819281eeSdp-arm if (fp == NULL)
309819281eeSdp-arm log_err("fopen %s", filename);
310819281eeSdp-arm
311819281eeSdp-arm if (fstat(fileno(fp), &st) == -1)
312819281eeSdp-arm log_err("fstat %s", filename);
313819281eeSdp-arm
31406e69f7cSAntonio Borneo st_size = st.st_size;
31506e69f7cSAntonio Borneo
31606e69f7cSAntonio Borneo #ifdef BLKGETSIZE64
31706e69f7cSAntonio Borneo if ((st.st_mode & S_IFBLK) != 0)
31806e69f7cSAntonio Borneo if (ioctl(fileno(fp), BLKGETSIZE64, &st_size) == -1)
31906e69f7cSAntonio Borneo log_err("ioctl %s", filename);
32006e69f7cSAntonio Borneo #endif
32106e69f7cSAntonio Borneo
32206e69f7cSAntonio Borneo buf = xmalloc(st_size, "failed to load file into memory");
32306e69f7cSAntonio Borneo if (fread(buf, 1, st_size, fp) != st_size)
324819281eeSdp-arm log_errx("Failed to read %s", filename);
32506e69f7cSAntonio Borneo bufend = buf + st_size;
326819281eeSdp-arm fclose(fp);
327819281eeSdp-arm
32806e69f7cSAntonio Borneo if (st_size < sizeof(fip_toc_header_t))
329819281eeSdp-arm log_errx("FIP %s is truncated", filename);
330819281eeSdp-arm
331819281eeSdp-arm toc_header = (fip_toc_header_t *)buf;
332819281eeSdp-arm toc_entry = (fip_toc_entry_t *)(toc_header + 1);
333819281eeSdp-arm
334819281eeSdp-arm if (toc_header->name != TOC_HEADER_NAME)
335819281eeSdp-arm log_errx("%s is not a FIP file", filename);
336819281eeSdp-arm
337819281eeSdp-arm /* Return the ToC header if the caller wants it. */
338819281eeSdp-arm if (toc_header_out != NULL)
339819281eeSdp-arm *toc_header_out = *toc_header;
340819281eeSdp-arm
341819281eeSdp-arm /* Walk through each ToC entry in the file. */
342819281eeSdp-arm while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) {
343fcab6bbeSdp-arm image_t *image;
344fcab6bbeSdp-arm image_desc_t *desc;
345fcab6bbeSdp-arm
346819281eeSdp-arm /* Found the ToC terminator, we are done. */
347819281eeSdp-arm if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) {
348819281eeSdp-arm terminated = 1;
349819281eeSdp-arm break;
350819281eeSdp-arm }
351819281eeSdp-arm
352819281eeSdp-arm /*
353819281eeSdp-arm * Build a new image out of the ToC entry and add it to the
354819281eeSdp-arm * table of images.
355819281eeSdp-arm */
35611c0a4ffSMasahiro Yamada image = xzalloc(sizeof(*image),
357a22f6285Sdp-arm "failed to allocate memory for image");
35865caa3d0SMasahiro Yamada image->toc_e = *toc_entry;
359a22f6285Sdp-arm image->buffer = xmalloc(toc_entry->size,
360a22f6285Sdp-arm "failed to allocate image buffer, is FIP file corrupted?");
361819281eeSdp-arm /* Overflow checks before memory copy. */
362819281eeSdp-arm if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address)
36306e69f7cSAntonio Borneo log_errx("FIP %s is corrupted: entry size exceeds 64 bit address space",
36406e69f7cSAntonio Borneo filename);
36506e69f7cSAntonio Borneo if (toc_entry->size + toc_entry->offset_address > st_size)
36606e69f7cSAntonio Borneo log_errx("FIP %s is corrupted: entry size exceeds FIP file size",
36706e69f7cSAntonio Borneo filename);
368819281eeSdp-arm
369819281eeSdp-arm memcpy(image->buffer, buf + toc_entry->offset_address,
370819281eeSdp-arm toc_entry->size);
371819281eeSdp-arm
372fcab6bbeSdp-arm /* If this is an unknown image, create a descriptor for it. */
37365caa3d0SMasahiro Yamada desc = lookup_image_desc_from_uuid(&toc_entry->uuid);
374fcab6bbeSdp-arm if (desc == NULL) {
375fcab6bbeSdp-arm char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
376fcab6bbeSdp-arm
37765caa3d0SMasahiro Yamada uuid_to_str(name, sizeof(name), &toc_entry->uuid);
378fcab6bbeSdp-arm snprintf(filename, sizeof(filename), "%s%s",
379fcab6bbeSdp-arm name, ".bin");
38065caa3d0SMasahiro Yamada desc = new_image_desc(&toc_entry->uuid, name, "blob");
381fcab6bbeSdp-arm desc->action = DO_UNPACK;
382fcab6bbeSdp-arm desc->action_arg = xstrdup(filename,
383fcab6bbeSdp-arm "failed to allocate memory for blob filename");
384fcab6bbeSdp-arm add_image_desc(desc);
385fcab6bbeSdp-arm }
386fcab6bbeSdp-arm
387b9589fe5Sdp-arm assert(desc->image == NULL);
388b9589fe5Sdp-arm desc->image = image;
389819281eeSdp-arm
390819281eeSdp-arm toc_entry++;
391819281eeSdp-arm }
392819281eeSdp-arm
393819281eeSdp-arm if (terminated == 0)
394819281eeSdp-arm log_errx("FIP %s does not have a ToC terminator entry",
395819281eeSdp-arm filename);
396819281eeSdp-arm free(buf);
397819281eeSdp-arm return 0;
398819281eeSdp-arm }
399819281eeSdp-arm
read_image_from_file(const uuid_t * uuid,const char * filename)40060b499feSdp-arm static image_t *read_image_from_file(const uuid_t *uuid, const char *filename)
401819281eeSdp-arm {
40296851114SEvan Lloyd struct BLD_PLAT_STAT st;
403819281eeSdp-arm image_t *image;
404819281eeSdp-arm FILE *fp;
405819281eeSdp-arm
406b04efcceSdp-arm assert(uuid != NULL);
40796851114SEvan Lloyd assert(filename != NULL);
408b04efcceSdp-arm
40955745deaSEvan Lloyd fp = fopen(filename, "rb");
410819281eeSdp-arm if (fp == NULL)
411819281eeSdp-arm log_err("fopen %s", filename);
412819281eeSdp-arm
413819281eeSdp-arm if (fstat(fileno(fp), &st) == -1)
414819281eeSdp-arm log_errx("fstat %s", filename);
415819281eeSdp-arm
41611c0a4ffSMasahiro Yamada image = xzalloc(sizeof(*image), "failed to allocate memory for image");
41765caa3d0SMasahiro Yamada image->toc_e.uuid = *uuid;
418a22f6285Sdp-arm image->buffer = xmalloc(st.st_size, "failed to allocate image buffer");
419819281eeSdp-arm if (fread(image->buffer, 1, st.st_size, fp) != st.st_size)
420819281eeSdp-arm log_errx("Failed to read %s", filename);
42165caa3d0SMasahiro Yamada image->toc_e.size = st.st_size;
422819281eeSdp-arm
423819281eeSdp-arm fclose(fp);
424819281eeSdp-arm return image;
425819281eeSdp-arm }
426819281eeSdp-arm
write_image_to_file(const image_t * image,const char * filename)42760b499feSdp-arm static int write_image_to_file(const image_t *image, const char *filename)
428819281eeSdp-arm {
429819281eeSdp-arm FILE *fp;
430819281eeSdp-arm
43155745deaSEvan Lloyd fp = fopen(filename, "wb");
432819281eeSdp-arm if (fp == NULL)
433819281eeSdp-arm log_err("fopen");
43465caa3d0SMasahiro Yamada xfwrite(image->buffer, image->toc_e.size, fp, filename);
435819281eeSdp-arm fclose(fp);
436819281eeSdp-arm return 0;
437819281eeSdp-arm }
438819281eeSdp-arm
add_opt(struct option * opts,size_t * nr_opts,const char * name,int has_arg,int val)439e0f083a0Sdp-arm static struct option *add_opt(struct option *opts, size_t *nr_opts,
440e0f083a0Sdp-arm const char *name, int has_arg, int val)
441819281eeSdp-arm {
442e0f083a0Sdp-arm opts = realloc(opts, (*nr_opts + 1) * sizeof(*opts));
443e0f083a0Sdp-arm if (opts == NULL)
444e0f083a0Sdp-arm log_err("realloc");
445e0f083a0Sdp-arm opts[*nr_opts].name = name;
446e0f083a0Sdp-arm opts[*nr_opts].has_arg = has_arg;
447e0f083a0Sdp-arm opts[*nr_opts].flag = NULL;
448e0f083a0Sdp-arm opts[*nr_opts].val = val;
449e0f083a0Sdp-arm ++*nr_opts;
450e0f083a0Sdp-arm return opts;
451819281eeSdp-arm }
452819281eeSdp-arm
fill_common_opts(struct option * opts,size_t * nr_opts,int has_arg)453e0f083a0Sdp-arm static struct option *fill_common_opts(struct option *opts, size_t *nr_opts,
454e0f083a0Sdp-arm int has_arg)
455819281eeSdp-arm {
456e0f083a0Sdp-arm image_desc_t *desc;
457e0f083a0Sdp-arm
458e0f083a0Sdp-arm for (desc = image_desc_head; desc != NULL; desc = desc->next)
459e0f083a0Sdp-arm opts = add_opt(opts, nr_opts, desc->cmdline_name, has_arg,
460e0f083a0Sdp-arm OPT_TOC_ENTRY);
461e0f083a0Sdp-arm return opts;
462819281eeSdp-arm }
463819281eeSdp-arm
4644d4fec28SOlivier Deprez #if !STATIC
md_print(const unsigned char * md,size_t len)465e0f083a0Sdp-arm static void md_print(const unsigned char *md, size_t len)
4669df69ba3Sdp-arm {
4679df69ba3Sdp-arm size_t i;
4689df69ba3Sdp-arm
4699df69ba3Sdp-arm for (i = 0; i < len; i++)
4709df69ba3Sdp-arm printf("%02x", md[i]);
4719df69ba3Sdp-arm }
4724d4fec28SOlivier Deprez #endif
4739df69ba3Sdp-arm
info_cmd(int argc,char * argv[])474819281eeSdp-arm static int info_cmd(int argc, char *argv[])
475819281eeSdp-arm {
476b9589fe5Sdp-arm image_desc_t *desc;
477819281eeSdp-arm fip_toc_header_t toc_header;
478819281eeSdp-arm
479819281eeSdp-arm if (argc != 2)
4804e500525SLeonardo Sandoval info_usage(EXIT_FAILURE);
481819281eeSdp-arm argc--, argv++;
482819281eeSdp-arm
483819281eeSdp-arm parse_fip(argv[0], &toc_header);
484819281eeSdp-arm
485819281eeSdp-arm if (verbose) {
486819281eeSdp-arm log_dbgx("toc_header[name]: 0x%llX",
487819281eeSdp-arm (unsigned long long)toc_header.name);
488819281eeSdp-arm log_dbgx("toc_header[serial_number]: 0x%llX",
489819281eeSdp-arm (unsigned long long)toc_header.serial_number);
490819281eeSdp-arm log_dbgx("toc_header[flags]: 0x%llX",
491819281eeSdp-arm (unsigned long long)toc_header.flags);
492819281eeSdp-arm }
493819281eeSdp-arm
494b9589fe5Sdp-arm for (desc = image_desc_head; desc != NULL; desc = desc->next) {
495b9589fe5Sdp-arm image_t *image = desc->image;
496b04efcceSdp-arm
497b9589fe5Sdp-arm if (image == NULL)
498b9589fe5Sdp-arm continue;
49965caa3d0SMasahiro Yamada printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"--%s\"",
50065caa3d0SMasahiro Yamada desc->name,
50165caa3d0SMasahiro Yamada (unsigned long long)image->toc_e.offset_address,
50265caa3d0SMasahiro Yamada (unsigned long long)image->toc_e.size,
503e0f083a0Sdp-arm desc->cmdline_name);
5044d4fec28SOlivier Deprez
5054d4fec28SOlivier Deprez /*
5064d4fec28SOlivier Deprez * Omit this informative code portion for:
5074d4fec28SOlivier Deprez * Visual Studio missing SHA256.
5084d4fec28SOlivier Deprez * Statically linked builds.
5094d4fec28SOlivier Deprez */
5104d4fec28SOlivier Deprez #if !defined(_MSC_VER) && !STATIC
5119df69ba3Sdp-arm if (verbose) {
5129df69ba3Sdp-arm unsigned char md[SHA256_DIGEST_LENGTH];
5139df69ba3Sdp-arm
51465caa3d0SMasahiro Yamada SHA256(image->buffer, image->toc_e.size, md);
5159df69ba3Sdp-arm printf(", sha256=");
5169df69ba3Sdp-arm md_print(md, sizeof(md));
5179df69ba3Sdp-arm }
51896851114SEvan Lloyd #endif
519819281eeSdp-arm putchar('\n');
520819281eeSdp-arm }
521819281eeSdp-arm
522819281eeSdp-arm return 0;
523819281eeSdp-arm }
524819281eeSdp-arm
info_usage(int exit_status)5254e500525SLeonardo Sandoval static void info_usage(int exit_status)
526819281eeSdp-arm {
527819281eeSdp-arm printf("fiptool info FIP_FILENAME\n");
5284e500525SLeonardo Sandoval exit(exit_status);
529819281eeSdp-arm }
530819281eeSdp-arm
pack_images(const char * filename,uint64_t toc_flags,unsigned long align)5311c75d5dfSMasahiro Yamada static int pack_images(const char *filename, uint64_t toc_flags, unsigned long align)
532819281eeSdp-arm {
533819281eeSdp-arm FILE *fp;
534b9589fe5Sdp-arm image_desc_t *desc;
535819281eeSdp-arm fip_toc_header_t *toc_header;
536819281eeSdp-arm fip_toc_entry_t *toc_entry;
537819281eeSdp-arm char *buf;
538880b9e8bSRoberto Vargas uint64_t entry_offset, buf_size, payload_size = 0, pad_size;
539b9589fe5Sdp-arm size_t nr_images = 0;
540b9589fe5Sdp-arm
541b9589fe5Sdp-arm for (desc = image_desc_head; desc != NULL; desc = desc->next)
542b9589fe5Sdp-arm if (desc->image != NULL)
543b9589fe5Sdp-arm nr_images++;
544819281eeSdp-arm
545819281eeSdp-arm buf_size = sizeof(fip_toc_header_t) +
546819281eeSdp-arm sizeof(fip_toc_entry_t) * (nr_images + 1);
547819281eeSdp-arm buf = calloc(1, buf_size);
548819281eeSdp-arm if (buf == NULL)
549819281eeSdp-arm log_err("calloc");
550819281eeSdp-arm
551819281eeSdp-arm /* Build up header and ToC entries from the image table. */
552819281eeSdp-arm toc_header = (fip_toc_header_t *)buf;
553819281eeSdp-arm toc_header->name = TOC_HEADER_NAME;
554819281eeSdp-arm toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
555819281eeSdp-arm toc_header->flags = toc_flags;
556819281eeSdp-arm
557819281eeSdp-arm toc_entry = (fip_toc_entry_t *)(toc_header + 1);
558819281eeSdp-arm
559819281eeSdp-arm entry_offset = buf_size;
560b9589fe5Sdp-arm for (desc = image_desc_head; desc != NULL; desc = desc->next) {
561b9589fe5Sdp-arm image_t *image = desc->image;
562b9589fe5Sdp-arm
563ab556c9cSManish V Badarkhe if (image == NULL || (image->toc_e.size == 0ULL))
564b9589fe5Sdp-arm continue;
56565caa3d0SMasahiro Yamada payload_size += image->toc_e.size;
5661c75d5dfSMasahiro Yamada entry_offset = (entry_offset + align - 1) & ~(align - 1);
56765caa3d0SMasahiro Yamada image->toc_e.offset_address = entry_offset;
56865caa3d0SMasahiro Yamada *toc_entry++ = image->toc_e;
56965caa3d0SMasahiro Yamada entry_offset += image->toc_e.size;
570819281eeSdp-arm }
571819281eeSdp-arm
572880b9e8bSRoberto Vargas /*
573880b9e8bSRoberto Vargas * Append a null uuid entry to mark the end of ToC entries.
574880b9e8bSRoberto Vargas * NOTE the offset address for the last toc_entry must match the fip
575880b9e8bSRoberto Vargas * size.
576880b9e8bSRoberto Vargas */
57765caa3d0SMasahiro Yamada memset(toc_entry, 0, sizeof(*toc_entry));
578880b9e8bSRoberto Vargas toc_entry->offset_address = (entry_offset + align - 1) & ~(align - 1);
579819281eeSdp-arm
580819281eeSdp-arm /* Generate the FIP file. */
58155745deaSEvan Lloyd fp = fopen(filename, "wb");
582819281eeSdp-arm if (fp == NULL)
583819281eeSdp-arm log_err("fopen %s", filename);
584819281eeSdp-arm
585819281eeSdp-arm if (verbose)
586819281eeSdp-arm log_dbgx("Metadata size: %zu bytes", buf_size);
587819281eeSdp-arm
588a1da83f5SMasahiro Yamada xfwrite(buf, buf_size, fp, filename);
589819281eeSdp-arm
590819281eeSdp-arm if (verbose)
591819281eeSdp-arm log_dbgx("Payload size: %zu bytes", payload_size);
592819281eeSdp-arm
593b9589fe5Sdp-arm for (desc = image_desc_head; desc != NULL; desc = desc->next) {
594b9589fe5Sdp-arm image_t *image = desc->image;
595b9589fe5Sdp-arm
596b9589fe5Sdp-arm if (image == NULL)
597b9589fe5Sdp-arm continue;
5981c75d5dfSMasahiro Yamada if (fseek(fp, image->toc_e.offset_address, SEEK_SET))
5991c75d5dfSMasahiro Yamada log_errx("Failed to set file position");
6001c75d5dfSMasahiro Yamada
60165caa3d0SMasahiro Yamada xfwrite(image->buffer, image->toc_e.size, fp, filename);
6021c75d5dfSMasahiro Yamada }
603819281eeSdp-arm
604880b9e8bSRoberto Vargas if (fseek(fp, entry_offset, SEEK_SET))
605880b9e8bSRoberto Vargas log_errx("Failed to set file position");
606880b9e8bSRoberto Vargas
607880b9e8bSRoberto Vargas pad_size = toc_entry->offset_address - entry_offset;
608880b9e8bSRoberto Vargas while (pad_size--)
609880b9e8bSRoberto Vargas fputc(0x0, fp);
610880b9e8bSRoberto Vargas
6118e4cdd22SAndreas Färber free(buf);
612819281eeSdp-arm fclose(fp);
613819281eeSdp-arm return 0;
614819281eeSdp-arm }
615819281eeSdp-arm
616819281eeSdp-arm /*
617819281eeSdp-arm * This function is shared between the create and update subcommands.
618819281eeSdp-arm * The difference between the two subcommands is that when the FIP file
619819281eeSdp-arm * is created, the parsing of an existing FIP is skipped. This results
620819281eeSdp-arm * in update_fip() creating the new FIP file from scratch because the
621819281eeSdp-arm * internal image table is not populated.
622819281eeSdp-arm */
update_fip(void)623819281eeSdp-arm static void update_fip(void)
624819281eeSdp-arm {
625e0f083a0Sdp-arm image_desc_t *desc;
626819281eeSdp-arm
627819281eeSdp-arm /* Add or replace images in the FIP file. */
628e0f083a0Sdp-arm for (desc = image_desc_head; desc != NULL; desc = desc->next) {
629b9589fe5Sdp-arm image_t *image;
630fcab6bbeSdp-arm
631e0f083a0Sdp-arm if (desc->action != DO_PACK)
632819281eeSdp-arm continue;
633819281eeSdp-arm
634b9589fe5Sdp-arm image = read_image_from_file(&desc->uuid,
635e0f083a0Sdp-arm desc->action_arg);
636b9589fe5Sdp-arm if (desc->image != NULL) {
637e0f083a0Sdp-arm if (verbose) {
638fcab6bbeSdp-arm log_dbgx("Replacing %s with %s",
639e0f083a0Sdp-arm desc->cmdline_name,
640e0f083a0Sdp-arm desc->action_arg);
641e0f083a0Sdp-arm }
642b9589fe5Sdp-arm free(desc->image);
643b9589fe5Sdp-arm desc->image = image;
644819281eeSdp-arm } else {
645819281eeSdp-arm if (verbose)
646819281eeSdp-arm log_dbgx("Adding image %s",
647e0f083a0Sdp-arm desc->action_arg);
648b9589fe5Sdp-arm desc->image = image;
649819281eeSdp-arm }
650819281eeSdp-arm }
651819281eeSdp-arm }
652819281eeSdp-arm
parse_plat_toc_flags(const char * arg,unsigned long long * toc_flags)653e0f083a0Sdp-arm static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags)
654819281eeSdp-arm {
655819281eeSdp-arm unsigned long long flags;
656819281eeSdp-arm char *endptr;
657819281eeSdp-arm
658819281eeSdp-arm errno = 0;
659819281eeSdp-arm flags = strtoull(arg, &endptr, 16);
660819281eeSdp-arm if (*endptr != '\0' || flags > UINT16_MAX || errno != 0)
661819281eeSdp-arm log_errx("Invalid platform ToC flags: %s", arg);
662819281eeSdp-arm /* Platform ToC flags is a 16-bit field occupying bits [32-47]. */
663819281eeSdp-arm *toc_flags |= flags << 32;
664819281eeSdp-arm }
665819281eeSdp-arm
is_power_of_2(unsigned long x)6661c75d5dfSMasahiro Yamada static int is_power_of_2(unsigned long x)
6671c75d5dfSMasahiro Yamada {
6681c75d5dfSMasahiro Yamada return x && !(x & (x - 1));
6691c75d5dfSMasahiro Yamada }
6701c75d5dfSMasahiro Yamada
get_image_align(char * arg)6711c75d5dfSMasahiro Yamada static unsigned long get_image_align(char *arg)
6721c75d5dfSMasahiro Yamada {
6731c75d5dfSMasahiro Yamada char *endptr;
6741c75d5dfSMasahiro Yamada unsigned long align;
6751c75d5dfSMasahiro Yamada
6761c75d5dfSMasahiro Yamada errno = 0;
677fb5f7949SAndreas Färber align = strtoul(arg, &endptr, 0);
6781c75d5dfSMasahiro Yamada if (*endptr != '\0' || !is_power_of_2(align) || errno != 0)
6791c75d5dfSMasahiro Yamada log_errx("Invalid alignment: %s", arg);
6801c75d5dfSMasahiro Yamada
6811c75d5dfSMasahiro Yamada return align;
6821c75d5dfSMasahiro Yamada }
6831c75d5dfSMasahiro Yamada
parse_blob_opt(char * arg,uuid_t * uuid,char * filename,size_t len)684fcab6bbeSdp-arm static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len)
685fcab6bbeSdp-arm {
686fcab6bbeSdp-arm char *p;
687fcab6bbeSdp-arm
688fcab6bbeSdp-arm for (p = strtok(arg, ","); p != NULL; p = strtok(NULL, ",")) {
689fcab6bbeSdp-arm if (strncmp(p, "uuid=", strlen("uuid=")) == 0) {
690fcab6bbeSdp-arm p += strlen("uuid=");
691fcab6bbeSdp-arm uuid_from_str(uuid, p);
692fcab6bbeSdp-arm } else if (strncmp(p, "file=", strlen("file=")) == 0) {
693fcab6bbeSdp-arm p += strlen("file=");
694fcab6bbeSdp-arm snprintf(filename, len, "%s", p);
695fcab6bbeSdp-arm }
696fcab6bbeSdp-arm }
697fcab6bbeSdp-arm }
698fcab6bbeSdp-arm
create_cmd(int argc,char * argv[])699819281eeSdp-arm static int create_cmd(int argc, char *argv[])
700819281eeSdp-arm {
701e0f083a0Sdp-arm struct option *opts = NULL;
702e0f083a0Sdp-arm size_t nr_opts = 0;
703819281eeSdp-arm unsigned long long toc_flags = 0;
7041c75d5dfSMasahiro Yamada unsigned long align = 1;
705819281eeSdp-arm
706819281eeSdp-arm if (argc < 2)
7074e500525SLeonardo Sandoval create_usage(EXIT_FAILURE);
708819281eeSdp-arm
709e0f083a0Sdp-arm opts = fill_common_opts(opts, &nr_opts, required_argument);
710e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
711819281eeSdp-arm OPT_PLAT_TOC_FLAGS);
7121c75d5dfSMasahiro Yamada opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
713fcab6bbeSdp-arm opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
714e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, NULL, 0, 0);
715819281eeSdp-arm
716819281eeSdp-arm while (1) {
71720f87e78Sdp-arm int c, opt_index = 0;
718819281eeSdp-arm
719fcab6bbeSdp-arm c = getopt_long(argc, argv, "b:", opts, &opt_index);
720819281eeSdp-arm if (c == -1)
721819281eeSdp-arm break;
722819281eeSdp-arm
723819281eeSdp-arm switch (c) {
724819281eeSdp-arm case OPT_TOC_ENTRY: {
725e0f083a0Sdp-arm image_desc_t *desc;
726819281eeSdp-arm
727e0f083a0Sdp-arm desc = lookup_image_desc_from_opt(opts[opt_index].name);
728d02fcebeSdp-arm set_image_desc_action(desc, DO_PACK, optarg);
729819281eeSdp-arm break;
730819281eeSdp-arm }
731819281eeSdp-arm case OPT_PLAT_TOC_FLAGS:
732819281eeSdp-arm parse_plat_toc_flags(optarg, &toc_flags);
733819281eeSdp-arm break;
7341c75d5dfSMasahiro Yamada case OPT_ALIGN:
7351c75d5dfSMasahiro Yamada align = get_image_align(optarg);
7361c75d5dfSMasahiro Yamada break;
737fcab6bbeSdp-arm case 'b': {
738fcab6bbeSdp-arm char name[_UUID_STR_LEN + 1];
739fcab6bbeSdp-arm char filename[PATH_MAX] = { 0 };
74003364865SRoberto Vargas uuid_t uuid = uuid_null;
741fcab6bbeSdp-arm image_desc_t *desc;
742fcab6bbeSdp-arm
743fcab6bbeSdp-arm parse_blob_opt(optarg, &uuid,
744fcab6bbeSdp-arm filename, sizeof(filename));
745fcab6bbeSdp-arm
746fcab6bbeSdp-arm if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
747fcab6bbeSdp-arm filename[0] == '\0')
7484e500525SLeonardo Sandoval create_usage(EXIT_FAILURE);
749fcab6bbeSdp-arm
750fcab6bbeSdp-arm desc = lookup_image_desc_from_uuid(&uuid);
751d02fcebeSdp-arm if (desc == NULL) {
752fcab6bbeSdp-arm uuid_to_str(name, sizeof(name), &uuid);
753fcab6bbeSdp-arm desc = new_image_desc(&uuid, name, "blob");
754fcab6bbeSdp-arm add_image_desc(desc);
755fcab6bbeSdp-arm }
756d02fcebeSdp-arm set_image_desc_action(desc, DO_PACK, filename);
757fcab6bbeSdp-arm break;
758fcab6bbeSdp-arm }
759819281eeSdp-arm default:
7604e500525SLeonardo Sandoval create_usage(EXIT_FAILURE);
761819281eeSdp-arm }
762819281eeSdp-arm }
763819281eeSdp-arm argc -= optind;
764819281eeSdp-arm argv += optind;
765e0f083a0Sdp-arm free(opts);
766819281eeSdp-arm
767819281eeSdp-arm if (argc == 0)
7684e500525SLeonardo Sandoval create_usage(EXIT_SUCCESS);
769819281eeSdp-arm
770819281eeSdp-arm update_fip();
771819281eeSdp-arm
7721c75d5dfSMasahiro Yamada pack_images(argv[0], toc_flags, align);
773819281eeSdp-arm return 0;
774819281eeSdp-arm }
775819281eeSdp-arm
create_usage(int exit_status)7764e500525SLeonardo Sandoval static void create_usage(int exit_status)
777819281eeSdp-arm {
778819281eeSdp-arm toc_entry_t *toc_entry = toc_entries;
779819281eeSdp-arm
780ee079320SMasahiro Yamada printf("fiptool create [opts] FIP_FILENAME\n");
781ee079320SMasahiro Yamada printf("\n");
782ee079320SMasahiro Yamada printf("Options:\n");
7831c75d5dfSMasahiro Yamada printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
784802b42a0SMasahiro Yamada printf(" --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n");
785802b42a0SMasahiro Yamada printf(" --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
78695d2b268SMasahiro Yamada printf("\n");
787819281eeSdp-arm printf("Specific images are packed with the following options:\n");
788819281eeSdp-arm for (; toc_entry->cmdline_name != NULL; toc_entry++)
789819281eeSdp-arm printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
790819281eeSdp-arm toc_entry->name);
7913527d6d2SPankaj Gupta #ifdef PLAT_DEF_FIP_UUID
7923527d6d2SPankaj Gupta toc_entry = plat_def_toc_entries;
7933527d6d2SPankaj Gupta for (; toc_entry->cmdline_name != NULL; toc_entry++)
7943527d6d2SPankaj Gupta printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
7953527d6d2SPankaj Gupta toc_entry->name);
7963527d6d2SPankaj Gupta #endif
7974e500525SLeonardo Sandoval exit(exit_status);
798819281eeSdp-arm }
799819281eeSdp-arm
update_cmd(int argc,char * argv[])800819281eeSdp-arm static int update_cmd(int argc, char *argv[])
801819281eeSdp-arm {
802e0f083a0Sdp-arm struct option *opts = NULL;
803e0f083a0Sdp-arm size_t nr_opts = 0;
804fcab6bbeSdp-arm char outfile[PATH_MAX] = { 0 };
805819281eeSdp-arm fip_toc_header_t toc_header = { 0 };
806819281eeSdp-arm unsigned long long toc_flags = 0;
8071c75d5dfSMasahiro Yamada unsigned long align = 1;
808819281eeSdp-arm int pflag = 0;
809819281eeSdp-arm
810819281eeSdp-arm if (argc < 2)
8114e500525SLeonardo Sandoval update_usage(EXIT_FAILURE);
812819281eeSdp-arm
813e0f083a0Sdp-arm opts = fill_common_opts(opts, &nr_opts, required_argument);
8141c75d5dfSMasahiro Yamada opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
815fcab6bbeSdp-arm opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
816e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
817e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
818819281eeSdp-arm OPT_PLAT_TOC_FLAGS);
819e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, NULL, 0, 0);
820819281eeSdp-arm
821819281eeSdp-arm while (1) {
82220f87e78Sdp-arm int c, opt_index = 0;
823819281eeSdp-arm
824fcab6bbeSdp-arm c = getopt_long(argc, argv, "b:o:", opts, &opt_index);
825819281eeSdp-arm if (c == -1)
826819281eeSdp-arm break;
827819281eeSdp-arm
828819281eeSdp-arm switch (c) {
829819281eeSdp-arm case OPT_TOC_ENTRY: {
830e0f083a0Sdp-arm image_desc_t *desc;
831819281eeSdp-arm
832e0f083a0Sdp-arm desc = lookup_image_desc_from_opt(opts[opt_index].name);
833d02fcebeSdp-arm set_image_desc_action(desc, DO_PACK, optarg);
834819281eeSdp-arm break;
835819281eeSdp-arm }
836e0f083a0Sdp-arm case OPT_PLAT_TOC_FLAGS:
837819281eeSdp-arm parse_plat_toc_flags(optarg, &toc_flags);
838819281eeSdp-arm pflag = 1;
839819281eeSdp-arm break;
840fcab6bbeSdp-arm case 'b': {
841fcab6bbeSdp-arm char name[_UUID_STR_LEN + 1];
842fcab6bbeSdp-arm char filename[PATH_MAX] = { 0 };
84303364865SRoberto Vargas uuid_t uuid = uuid_null;
844fcab6bbeSdp-arm image_desc_t *desc;
845fcab6bbeSdp-arm
846fcab6bbeSdp-arm parse_blob_opt(optarg, &uuid,
847fcab6bbeSdp-arm filename, sizeof(filename));
848fcab6bbeSdp-arm
849fcab6bbeSdp-arm if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
850fcab6bbeSdp-arm filename[0] == '\0')
8514e500525SLeonardo Sandoval update_usage(EXIT_FAILURE);
852fcab6bbeSdp-arm
853fcab6bbeSdp-arm desc = lookup_image_desc_from_uuid(&uuid);
854d02fcebeSdp-arm if (desc == NULL) {
855fcab6bbeSdp-arm uuid_to_str(name, sizeof(name), &uuid);
856fcab6bbeSdp-arm desc = new_image_desc(&uuid, name, "blob");
857fcab6bbeSdp-arm add_image_desc(desc);
858fcab6bbeSdp-arm }
859d02fcebeSdp-arm set_image_desc_action(desc, DO_PACK, filename);
860fcab6bbeSdp-arm break;
861fcab6bbeSdp-arm }
8621c75d5dfSMasahiro Yamada case OPT_ALIGN:
8631c75d5dfSMasahiro Yamada align = get_image_align(optarg);
8641c75d5dfSMasahiro Yamada break;
865819281eeSdp-arm case 'o':
866819281eeSdp-arm snprintf(outfile, sizeof(outfile), "%s", optarg);
867819281eeSdp-arm break;
868819281eeSdp-arm default:
8694e500525SLeonardo Sandoval update_usage(EXIT_FAILURE);
870819281eeSdp-arm }
871819281eeSdp-arm }
872819281eeSdp-arm argc -= optind;
873819281eeSdp-arm argv += optind;
874e0f083a0Sdp-arm free(opts);
875819281eeSdp-arm
876819281eeSdp-arm if (argc == 0)
8774e500525SLeonardo Sandoval update_usage(EXIT_SUCCESS);
878819281eeSdp-arm
879819281eeSdp-arm if (outfile[0] == '\0')
880819281eeSdp-arm snprintf(outfile, sizeof(outfile), "%s", argv[0]);
881819281eeSdp-arm
88240866aafSMasahiro Yamada if (access(argv[0], F_OK) == 0)
883819281eeSdp-arm parse_fip(argv[0], &toc_header);
884819281eeSdp-arm
885819281eeSdp-arm if (pflag)
886819281eeSdp-arm toc_header.flags &= ~(0xffffULL << 32);
887819281eeSdp-arm toc_flags = (toc_header.flags |= toc_flags);
888819281eeSdp-arm
889819281eeSdp-arm update_fip();
890819281eeSdp-arm
8911c75d5dfSMasahiro Yamada pack_images(outfile, toc_flags, align);
892819281eeSdp-arm return 0;
893819281eeSdp-arm }
894819281eeSdp-arm
update_usage(int exit_status)8954e500525SLeonardo Sandoval static void update_usage(int exit_status)
896819281eeSdp-arm {
897819281eeSdp-arm toc_entry_t *toc_entry = toc_entries;
898819281eeSdp-arm
899ee079320SMasahiro Yamada printf("fiptool update [opts] FIP_FILENAME\n");
900ee079320SMasahiro Yamada printf("\n");
901ee079320SMasahiro Yamada printf("Options:\n");
9021c75d5dfSMasahiro Yamada printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
903802b42a0SMasahiro Yamada printf(" --blob uuid=...,file=...\tAdd or update an image with the given UUID pointed to by file.\n");
904819281eeSdp-arm printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n");
905802b42a0SMasahiro Yamada printf(" --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
90695d2b268SMasahiro Yamada printf("\n");
907819281eeSdp-arm printf("Specific images are packed with the following options:\n");
908819281eeSdp-arm for (; toc_entry->cmdline_name != NULL; toc_entry++)
909819281eeSdp-arm printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
910819281eeSdp-arm toc_entry->name);
9113527d6d2SPankaj Gupta #ifdef PLAT_DEF_FIP_UUID
9123527d6d2SPankaj Gupta toc_entry = plat_def_toc_entries;
9133527d6d2SPankaj Gupta for (; toc_entry->cmdline_name != NULL; toc_entry++)
9143527d6d2SPankaj Gupta printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
9153527d6d2SPankaj Gupta toc_entry->name);
9163527d6d2SPankaj Gupta #endif
9174e500525SLeonardo Sandoval exit(exit_status);
918819281eeSdp-arm }
919819281eeSdp-arm
unpack_cmd(int argc,char * argv[])920819281eeSdp-arm static int unpack_cmd(int argc, char *argv[])
921819281eeSdp-arm {
922e0f083a0Sdp-arm struct option *opts = NULL;
923e0f083a0Sdp-arm size_t nr_opts = 0;
924fcab6bbeSdp-arm char outdir[PATH_MAX] = { 0 };
925e0f083a0Sdp-arm image_desc_t *desc;
926819281eeSdp-arm int fflag = 0;
927819281eeSdp-arm int unpack_all = 1;
928819281eeSdp-arm
929819281eeSdp-arm if (argc < 2)
9304e500525SLeonardo Sandoval unpack_usage(EXIT_FAILURE);
931819281eeSdp-arm
932e0f083a0Sdp-arm opts = fill_common_opts(opts, &nr_opts, required_argument);
933fcab6bbeSdp-arm opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
934e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
935e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
936e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, NULL, 0, 0);
937819281eeSdp-arm
938819281eeSdp-arm while (1) {
93920f87e78Sdp-arm int c, opt_index = 0;
940819281eeSdp-arm
941fcab6bbeSdp-arm c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
942819281eeSdp-arm if (c == -1)
943819281eeSdp-arm break;
944819281eeSdp-arm
945819281eeSdp-arm switch (c) {
946e0f083a0Sdp-arm case OPT_TOC_ENTRY: {
947e0f083a0Sdp-arm image_desc_t *desc;
948e0f083a0Sdp-arm
949e0f083a0Sdp-arm desc = lookup_image_desc_from_opt(opts[opt_index].name);
950d02fcebeSdp-arm set_image_desc_action(desc, DO_UNPACK, optarg);
951e0f083a0Sdp-arm unpack_all = 0;
952819281eeSdp-arm break;
953e0f083a0Sdp-arm }
954fcab6bbeSdp-arm case 'b': {
955fcab6bbeSdp-arm char name[_UUID_STR_LEN + 1];
956fcab6bbeSdp-arm char filename[PATH_MAX] = { 0 };
95703364865SRoberto Vargas uuid_t uuid = uuid_null;
958fcab6bbeSdp-arm image_desc_t *desc;
959fcab6bbeSdp-arm
960fcab6bbeSdp-arm parse_blob_opt(optarg, &uuid,
961fcab6bbeSdp-arm filename, sizeof(filename));
962fcab6bbeSdp-arm
963fcab6bbeSdp-arm if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
964fcab6bbeSdp-arm filename[0] == '\0')
9654e500525SLeonardo Sandoval unpack_usage(EXIT_FAILURE);
966fcab6bbeSdp-arm
967fcab6bbeSdp-arm desc = lookup_image_desc_from_uuid(&uuid);
968d02fcebeSdp-arm if (desc == NULL) {
969fcab6bbeSdp-arm uuid_to_str(name, sizeof(name), &uuid);
970fcab6bbeSdp-arm desc = new_image_desc(&uuid, name, "blob");
971fcab6bbeSdp-arm add_image_desc(desc);
972fcab6bbeSdp-arm }
973d02fcebeSdp-arm set_image_desc_action(desc, DO_UNPACK, filename);
974fcab6bbeSdp-arm unpack_all = 0;
975fcab6bbeSdp-arm break;
976fcab6bbeSdp-arm }
977819281eeSdp-arm case 'f':
978819281eeSdp-arm fflag = 1;
979819281eeSdp-arm break;
980819281eeSdp-arm case 'o':
981819281eeSdp-arm snprintf(outdir, sizeof(outdir), "%s", optarg);
982819281eeSdp-arm break;
983819281eeSdp-arm default:
9844e500525SLeonardo Sandoval unpack_usage(EXIT_FAILURE);
985819281eeSdp-arm }
986819281eeSdp-arm }
987819281eeSdp-arm argc -= optind;
988819281eeSdp-arm argv += optind;
989e0f083a0Sdp-arm free(opts);
990819281eeSdp-arm
991819281eeSdp-arm if (argc == 0)
9924e500525SLeonardo Sandoval unpack_usage(EXIT_SUCCESS);
993819281eeSdp-arm
994819281eeSdp-arm parse_fip(argv[0], NULL);
995819281eeSdp-arm
996819281eeSdp-arm if (outdir[0] != '\0')
997819281eeSdp-arm if (chdir(outdir) == -1)
998819281eeSdp-arm log_err("chdir %s", outdir);
999819281eeSdp-arm
1000819281eeSdp-arm /* Unpack all specified images. */
1001e0f083a0Sdp-arm for (desc = image_desc_head; desc != NULL; desc = desc->next) {
1002fcab6bbeSdp-arm char file[PATH_MAX];
1003b9589fe5Sdp-arm image_t *image = desc->image;
1004b04efcceSdp-arm
1005e0f083a0Sdp-arm if (!unpack_all && desc->action != DO_UNPACK)
1006819281eeSdp-arm continue;
1007819281eeSdp-arm
1008819281eeSdp-arm /* Build filename. */
1009e0f083a0Sdp-arm if (desc->action_arg == NULL)
1010819281eeSdp-arm snprintf(file, sizeof(file), "%s.bin",
1011e0f083a0Sdp-arm desc->cmdline_name);
1012819281eeSdp-arm else
1013819281eeSdp-arm snprintf(file, sizeof(file), "%s",
1014e0f083a0Sdp-arm desc->action_arg);
1015819281eeSdp-arm
1016b04efcceSdp-arm if (image == NULL) {
1017b04efcceSdp-arm if (!unpack_all)
1018fcab6bbeSdp-arm log_warnx("%s does not exist in %s",
1019819281eeSdp-arm file, argv[0]);
1020819281eeSdp-arm continue;
1021819281eeSdp-arm }
1022819281eeSdp-arm
1023819281eeSdp-arm if (access(file, F_OK) != 0 || fflag) {
1024819281eeSdp-arm if (verbose)
1025819281eeSdp-arm log_dbgx("Unpacking %s", file);
1026b04efcceSdp-arm write_image_to_file(image, file);
1027819281eeSdp-arm } else {
1028819281eeSdp-arm log_warnx("File %s already exists, use --force to overwrite it",
1029819281eeSdp-arm file);
1030819281eeSdp-arm }
1031819281eeSdp-arm }
1032819281eeSdp-arm
1033819281eeSdp-arm return 0;
1034819281eeSdp-arm }
1035819281eeSdp-arm
unpack_usage(int exit_status)10364e500525SLeonardo Sandoval static void unpack_usage(int exit_status)
1037819281eeSdp-arm {
1038819281eeSdp-arm toc_entry_t *toc_entry = toc_entries;
1039819281eeSdp-arm
1040ee079320SMasahiro Yamada printf("fiptool unpack [opts] FIP_FILENAME\n");
1041ee079320SMasahiro Yamada printf("\n");
1042ee079320SMasahiro Yamada printf("Options:\n");
1043802b42a0SMasahiro Yamada printf(" --blob uuid=...,file=...\tUnpack an image with the given UUID to file.\n");
1044802b42a0SMasahiro Yamada printf(" --force\t\t\tIf the output file already exists, use --force to overwrite it.\n");
1045fcab6bbeSdp-arm printf(" --out path\t\t\tSet the output directory path.\n");
104695d2b268SMasahiro Yamada printf("\n");
1047819281eeSdp-arm printf("Specific images are unpacked with the following options:\n");
1048819281eeSdp-arm for (; toc_entry->cmdline_name != NULL; toc_entry++)
1049819281eeSdp-arm printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
1050819281eeSdp-arm toc_entry->name);
10513527d6d2SPankaj Gupta #ifdef PLAT_DEF_FIP_UUID
10523527d6d2SPankaj Gupta toc_entry = plat_def_toc_entries;
10533527d6d2SPankaj Gupta for (; toc_entry->cmdline_name != NULL; toc_entry++)
10543527d6d2SPankaj Gupta printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
10553527d6d2SPankaj Gupta toc_entry->name);
10563527d6d2SPankaj Gupta #endif
105795d2b268SMasahiro Yamada printf("\n");
1058819281eeSdp-arm printf("If no options are provided, all images will be unpacked.\n");
10594e500525SLeonardo Sandoval exit(exit_status);
1060819281eeSdp-arm }
1061819281eeSdp-arm
remove_cmd(int argc,char * argv[])1062819281eeSdp-arm static int remove_cmd(int argc, char *argv[])
1063819281eeSdp-arm {
1064e0f083a0Sdp-arm struct option *opts = NULL;
1065e0f083a0Sdp-arm size_t nr_opts = 0;
1066fcab6bbeSdp-arm char outfile[PATH_MAX] = { 0 };
1067819281eeSdp-arm fip_toc_header_t toc_header;
1068e0f083a0Sdp-arm image_desc_t *desc;
10691c75d5dfSMasahiro Yamada unsigned long align = 1;
1070819281eeSdp-arm int fflag = 0;
1071819281eeSdp-arm
1072819281eeSdp-arm if (argc < 2)
10734e500525SLeonardo Sandoval remove_usage(EXIT_FAILURE);
1074819281eeSdp-arm
1075e0f083a0Sdp-arm opts = fill_common_opts(opts, &nr_opts, no_argument);
10761c75d5dfSMasahiro Yamada opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
1077fcab6bbeSdp-arm opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
1078e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
1079e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
1080e0f083a0Sdp-arm opts = add_opt(opts, &nr_opts, NULL, 0, 0);
1081819281eeSdp-arm
1082819281eeSdp-arm while (1) {
108320f87e78Sdp-arm int c, opt_index = 0;
1084819281eeSdp-arm
1085fcab6bbeSdp-arm c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
1086819281eeSdp-arm if (c == -1)
1087819281eeSdp-arm break;
1088819281eeSdp-arm
1089819281eeSdp-arm switch (c) {
1090e0f083a0Sdp-arm case OPT_TOC_ENTRY: {
1091e0f083a0Sdp-arm image_desc_t *desc;
1092e0f083a0Sdp-arm
1093e0f083a0Sdp-arm desc = lookup_image_desc_from_opt(opts[opt_index].name);
1094d02fcebeSdp-arm set_image_desc_action(desc, DO_REMOVE, NULL);
1095819281eeSdp-arm break;
1096e0f083a0Sdp-arm }
10971c75d5dfSMasahiro Yamada case OPT_ALIGN:
10981c75d5dfSMasahiro Yamada align = get_image_align(optarg);
10991c75d5dfSMasahiro Yamada break;
1100fcab6bbeSdp-arm case 'b': {
1101fcab6bbeSdp-arm char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
110203364865SRoberto Vargas uuid_t uuid = uuid_null;
1103fcab6bbeSdp-arm image_desc_t *desc;
1104fcab6bbeSdp-arm
1105fcab6bbeSdp-arm parse_blob_opt(optarg, &uuid,
1106fcab6bbeSdp-arm filename, sizeof(filename));
1107fcab6bbeSdp-arm
1108fcab6bbeSdp-arm if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0)
11094e500525SLeonardo Sandoval remove_usage(EXIT_FAILURE);
1110fcab6bbeSdp-arm
1111fcab6bbeSdp-arm desc = lookup_image_desc_from_uuid(&uuid);
1112d02fcebeSdp-arm if (desc == NULL) {
1113fcab6bbeSdp-arm uuid_to_str(name, sizeof(name), &uuid);
1114fcab6bbeSdp-arm desc = new_image_desc(&uuid, name, "blob");
1115fcab6bbeSdp-arm add_image_desc(desc);
1116fcab6bbeSdp-arm }
1117d02fcebeSdp-arm set_image_desc_action(desc, DO_REMOVE, NULL);
1118fcab6bbeSdp-arm break;
1119fcab6bbeSdp-arm }
1120819281eeSdp-arm case 'f':
1121819281eeSdp-arm fflag = 1;
1122819281eeSdp-arm break;
1123819281eeSdp-arm case 'o':
1124819281eeSdp-arm snprintf(outfile, sizeof(outfile), "%s", optarg);
1125819281eeSdp-arm break;
1126819281eeSdp-arm default:
11274e500525SLeonardo Sandoval remove_usage(EXIT_FAILURE);
1128819281eeSdp-arm }
1129819281eeSdp-arm }
1130819281eeSdp-arm argc -= optind;
1131819281eeSdp-arm argv += optind;
1132e0f083a0Sdp-arm free(opts);
1133819281eeSdp-arm
1134819281eeSdp-arm if (argc == 0)
11354e500525SLeonardo Sandoval remove_usage(EXIT_SUCCESS);
1136819281eeSdp-arm
1137819281eeSdp-arm if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag)
1138819281eeSdp-arm log_errx("File %s already exists, use --force to overwrite it",
1139819281eeSdp-arm outfile);
1140819281eeSdp-arm
1141819281eeSdp-arm if (outfile[0] == '\0')
1142819281eeSdp-arm snprintf(outfile, sizeof(outfile), "%s", argv[0]);
1143819281eeSdp-arm
1144819281eeSdp-arm parse_fip(argv[0], &toc_header);
1145819281eeSdp-arm
1146e0f083a0Sdp-arm for (desc = image_desc_head; desc != NULL; desc = desc->next) {
1147e0f083a0Sdp-arm if (desc->action != DO_REMOVE)
1148819281eeSdp-arm continue;
1149fcab6bbeSdp-arm
1150b9589fe5Sdp-arm if (desc->image != NULL) {
1151819281eeSdp-arm if (verbose)
1152fcab6bbeSdp-arm log_dbgx("Removing %s",
1153e0f083a0Sdp-arm desc->cmdline_name);
1154b9589fe5Sdp-arm free(desc->image);
1155b9589fe5Sdp-arm desc->image = NULL;
1156819281eeSdp-arm } else {
1157fcab6bbeSdp-arm log_warnx("%s does not exist in %s",
1158e0f083a0Sdp-arm desc->cmdline_name, argv[0]);
1159819281eeSdp-arm }
1160819281eeSdp-arm }
1161819281eeSdp-arm
11621c75d5dfSMasahiro Yamada pack_images(outfile, toc_header.flags, align);
1163819281eeSdp-arm return 0;
1164819281eeSdp-arm }
1165819281eeSdp-arm
remove_usage(int exit_status)11664e500525SLeonardo Sandoval static void remove_usage(int exit_status)
1167819281eeSdp-arm {
1168819281eeSdp-arm toc_entry_t *toc_entry = toc_entries;
1169819281eeSdp-arm
1170ee079320SMasahiro Yamada printf("fiptool remove [opts] FIP_FILENAME\n");
1171ee079320SMasahiro Yamada printf("\n");
1172ee079320SMasahiro Yamada printf("Options:\n");
11731c75d5dfSMasahiro Yamada printf(" --align <value>\tEach image is aligned to <value> (default: 1).\n");
1174fcab6bbeSdp-arm printf(" --blob uuid=...\tRemove an image with the given UUID.\n");
1175802b42a0SMasahiro Yamada printf(" --force\t\tIf the output FIP file already exists, use --force to overwrite it.\n");
1176819281eeSdp-arm printf(" --out FIP_FILENAME\tSet an alternative output FIP file.\n");
117795d2b268SMasahiro Yamada printf("\n");
1178819281eeSdp-arm printf("Specific images are removed with the following options:\n");
1179819281eeSdp-arm for (; toc_entry->cmdline_name != NULL; toc_entry++)
1180819281eeSdp-arm printf(" --%-16s\t%s\n", toc_entry->cmdline_name,
1181819281eeSdp-arm toc_entry->name);
11823527d6d2SPankaj Gupta #ifdef PLAT_DEF_FIP_UUID
11833527d6d2SPankaj Gupta toc_entry = plat_def_toc_entries;
11843527d6d2SPankaj Gupta for (; toc_entry->cmdline_name != NULL; toc_entry++)
11853527d6d2SPankaj Gupta printf(" --%-16s\t%s\n", toc_entry->cmdline_name,
11863527d6d2SPankaj Gupta toc_entry->name);
11873527d6d2SPankaj Gupta #endif
11884e500525SLeonardo Sandoval exit(exit_status);
1189819281eeSdp-arm }
1190819281eeSdp-arm
version_cmd(int argc,char * argv[])1191819281eeSdp-arm static int version_cmd(int argc, char *argv[])
1192819281eeSdp-arm {
1193819281eeSdp-arm #ifdef VERSION
1194819281eeSdp-arm puts(VERSION);
1195819281eeSdp-arm #else
1196819281eeSdp-arm /* If built from fiptool directory, VERSION is not set. */
1197819281eeSdp-arm puts("Unknown version");
1198819281eeSdp-arm #endif
1199819281eeSdp-arm return 0;
1200819281eeSdp-arm }
1201819281eeSdp-arm
version_usage(int exit_status)12024e500525SLeonardo Sandoval static void version_usage(int exit_status)
1203819281eeSdp-arm {
1204819281eeSdp-arm printf("fiptool version\n");
12054e500525SLeonardo Sandoval exit(exit_status);
1206819281eeSdp-arm }
1207819281eeSdp-arm
help_cmd(int argc,char * argv[])1208819281eeSdp-arm static int help_cmd(int argc, char *argv[])
1209819281eeSdp-arm {
1210819281eeSdp-arm int i;
1211819281eeSdp-arm
1212819281eeSdp-arm if (argc < 2)
1213819281eeSdp-arm usage();
1214819281eeSdp-arm argc--, argv++;
1215819281eeSdp-arm
1216819281eeSdp-arm for (i = 0; i < NELEM(cmds); i++) {
1217819281eeSdp-arm if (strcmp(cmds[i].name, argv[0]) == 0 &&
121885ee2778Sdp-arm cmds[i].usage != NULL)
12194e500525SLeonardo Sandoval cmds[i].usage(EXIT_SUCCESS);
1220819281eeSdp-arm }
1221819281eeSdp-arm if (i == NELEM(cmds))
1222819281eeSdp-arm printf("No help for subcommand '%s'\n", argv[0]);
1223819281eeSdp-arm return 0;
1224819281eeSdp-arm }
1225819281eeSdp-arm
usage(void)1226819281eeSdp-arm static void usage(void)
1227819281eeSdp-arm {
12284f96a498SMasahiro Yamada printf("usage: fiptool [--verbose] <command> [<args>]\n");
1229819281eeSdp-arm printf("Global options supported:\n");
1230819281eeSdp-arm printf(" --verbose\tEnable verbose output for all commands.\n");
123195d2b268SMasahiro Yamada printf("\n");
1232819281eeSdp-arm printf("Commands supported:\n");
1233819281eeSdp-arm printf(" info\t\tList images contained in FIP.\n");
1234819281eeSdp-arm printf(" create\tCreate a new FIP with the given images.\n");
1235819281eeSdp-arm printf(" update\tUpdate an existing FIP with the given images.\n");
1236819281eeSdp-arm printf(" unpack\tUnpack images from FIP.\n");
1237819281eeSdp-arm printf(" remove\tRemove images from FIP.\n");
1238819281eeSdp-arm printf(" version\tShow fiptool version.\n");
1239819281eeSdp-arm printf(" help\t\tShow help for given command.\n");
12404e500525SLeonardo Sandoval exit(EXIT_SUCCESS);
1241819281eeSdp-arm }
1242819281eeSdp-arm
main(int argc,char * argv[])1243819281eeSdp-arm int main(int argc, char *argv[])
1244819281eeSdp-arm {
1245819281eeSdp-arm int i, ret = 0;
1246819281eeSdp-arm
1247cc672bb2Sdp-arm while (1) {
1248cc672bb2Sdp-arm int c, opt_index = 0;
1249cc672bb2Sdp-arm static struct option opts[] = {
1250cc672bb2Sdp-arm { "verbose", no_argument, NULL, 'v' },
1251cc672bb2Sdp-arm { NULL, no_argument, NULL, 0 }
1252cc672bb2Sdp-arm };
1253819281eeSdp-arm
1254cc672bb2Sdp-arm /*
1255cc672bb2Sdp-arm * Set POSIX mode so getopt stops at the first non-option
1256cc672bb2Sdp-arm * which is the subcommand.
1257cc672bb2Sdp-arm */
1258cc672bb2Sdp-arm c = getopt_long(argc, argv, "+v", opts, &opt_index);
1259cc672bb2Sdp-arm if (c == -1)
1260cc672bb2Sdp-arm break;
1261cc672bb2Sdp-arm
1262cc672bb2Sdp-arm switch (c) {
1263cc672bb2Sdp-arm case 'v':
1264819281eeSdp-arm verbose = 1;
1265cc672bb2Sdp-arm break;
1266cc672bb2Sdp-arm default:
1267c9cb4089SMasahiro Yamada usage();
1268819281eeSdp-arm }
1269cc672bb2Sdp-arm }
1270cc672bb2Sdp-arm argc -= optind;
1271cc672bb2Sdp-arm argv += optind;
1272cc672bb2Sdp-arm /* Reset optind for subsequent getopt processing. */
1273cc672bb2Sdp-arm optind = 0;
1274cc672bb2Sdp-arm
1275cc672bb2Sdp-arm if (argc == 0)
1276cc672bb2Sdp-arm usage();
1277819281eeSdp-arm
1278e0f083a0Sdp-arm fill_image_descs();
1279819281eeSdp-arm for (i = 0; i < NELEM(cmds); i++) {
1280819281eeSdp-arm if (strcmp(cmds[i].name, argv[0]) == 0) {
1281819281eeSdp-arm ret = cmds[i].handler(argc, argv);
1282819281eeSdp-arm break;
1283819281eeSdp-arm }
1284819281eeSdp-arm }
1285819281eeSdp-arm if (i == NELEM(cmds))
1286819281eeSdp-arm usage();
1287e0f083a0Sdp-arm free_image_descs();
1288819281eeSdp-arm return ret;
1289819281eeSdp-arm }
1290