xref: /rk3399_ARM-atf/tools/fiptool/fiptool.c (revision ab556c9c646f1b5f1b500449a5813a4eecdc0302)
1819281eeSdp-arm /*
22a6c1a8fSMasahiro Yamada  * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
3819281eeSdp-arm  *
482cb2c1aSdp-arm  * SPDX-License-Identifier: BSD-3-Clause
5819281eeSdp-arm  */
6819281eeSdp-arm 
7819281eeSdp-arm #include <sys/types.h>
8819281eeSdp-arm #include <sys/stat.h>
9819281eeSdp-arm 
10819281eeSdp-arm #include <assert.h>
11819281eeSdp-arm #include <errno.h>
12819281eeSdp-arm #include <limits.h>
13819281eeSdp-arm #include <stdarg.h>
14819281eeSdp-arm #include <stdint.h>
15819281eeSdp-arm #include <stdio.h>
16819281eeSdp-arm #include <stdlib.h>
17819281eeSdp-arm #include <string.h>
182a6c1a8fSMasahiro Yamada 
19819281eeSdp-arm #include "fiptool.h"
20819281eeSdp-arm #include "tbbr_config.h"
21819281eeSdp-arm 
22819281eeSdp-arm #define OPT_TOC_ENTRY 0
23819281eeSdp-arm #define OPT_PLAT_TOC_FLAGS 1
241c75d5dfSMasahiro Yamada #define OPT_ALIGN 2
25819281eeSdp-arm 
26819281eeSdp-arm static int info_cmd(int argc, char *argv[]);
274e500525SLeonardo Sandoval static void info_usage(int);
28819281eeSdp-arm static int create_cmd(int argc, char *argv[]);
294e500525SLeonardo Sandoval static void create_usage(int);
30819281eeSdp-arm static int update_cmd(int argc, char *argv[]);
314e500525SLeonardo Sandoval static void update_usage(int);
32819281eeSdp-arm static int unpack_cmd(int argc, char *argv[]);
334e500525SLeonardo Sandoval static void unpack_usage(int);
34819281eeSdp-arm static int remove_cmd(int argc, char *argv[]);
354e500525SLeonardo Sandoval static void remove_usage(int);
36819281eeSdp-arm static int version_cmd(int argc, char *argv[]);
374e500525SLeonardo Sandoval static void version_usage(int);
38819281eeSdp-arm static int help_cmd(int argc, char *argv[]);
39819281eeSdp-arm static void usage(void);
40819281eeSdp-arm 
41819281eeSdp-arm /* Available subcommands. */
42819281eeSdp-arm static cmd_t cmds[] = {
43819281eeSdp-arm 	{ .name = "info",    .handler = info_cmd,    .usage = info_usage    },
44819281eeSdp-arm 	{ .name = "create",  .handler = create_cmd,  .usage = create_usage  },
45819281eeSdp-arm 	{ .name = "update",  .handler = update_cmd,  .usage = update_usage  },
46819281eeSdp-arm 	{ .name = "unpack",  .handler = unpack_cmd,  .usage = unpack_usage  },
47819281eeSdp-arm 	{ .name = "remove",  .handler = remove_cmd,  .usage = remove_usage  },
48819281eeSdp-arm 	{ .name = "version", .handler = version_cmd, .usage = version_usage },
49819281eeSdp-arm 	{ .name = "help",    .handler = help_cmd,    .usage = NULL          },
50819281eeSdp-arm };
51819281eeSdp-arm 
52e0f083a0Sdp-arm static image_desc_t *image_desc_head;
53e0f083a0Sdp-arm static size_t nr_image_descs;
5403364865SRoberto Vargas static const uuid_t uuid_null;
55819281eeSdp-arm static int verbose;
56819281eeSdp-arm 
5760b499feSdp-arm static void vlog(int prio, const char *msg, va_list ap)
58819281eeSdp-arm {
59819281eeSdp-arm 	char *prefix[] = { "DEBUG", "WARN", "ERROR" };
60819281eeSdp-arm 
61819281eeSdp-arm 	fprintf(stderr, "%s: ", prefix[prio]);
62819281eeSdp-arm 	vfprintf(stderr, msg, ap);
63819281eeSdp-arm 	fputc('\n', stderr);
64819281eeSdp-arm }
65819281eeSdp-arm 
6660b499feSdp-arm static void log_dbgx(const char *msg, ...)
67819281eeSdp-arm {
68819281eeSdp-arm 	va_list ap;
69819281eeSdp-arm 
70819281eeSdp-arm 	va_start(ap, msg);
71819281eeSdp-arm 	vlog(LOG_DBG, msg, ap);
72819281eeSdp-arm 	va_end(ap);
73819281eeSdp-arm }
74819281eeSdp-arm 
7560b499feSdp-arm static void log_warnx(const char *msg, ...)
76819281eeSdp-arm {
77819281eeSdp-arm 	va_list ap;
78819281eeSdp-arm 
79819281eeSdp-arm 	va_start(ap, msg);
80819281eeSdp-arm 	vlog(LOG_WARN, msg, ap);
81819281eeSdp-arm 	va_end(ap);
82819281eeSdp-arm }
83819281eeSdp-arm 
8460b499feSdp-arm static void log_err(const char *msg, ...)
85819281eeSdp-arm {
86819281eeSdp-arm 	char buf[512];
87819281eeSdp-arm 	va_list ap;
88819281eeSdp-arm 
89819281eeSdp-arm 	va_start(ap, msg);
90819281eeSdp-arm 	snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno));
91819281eeSdp-arm 	vlog(LOG_ERR, buf, ap);
92819281eeSdp-arm 	va_end(ap);
93819281eeSdp-arm 	exit(1);
94819281eeSdp-arm }
95819281eeSdp-arm 
9660b499feSdp-arm static void log_errx(const char *msg, ...)
97819281eeSdp-arm {
98819281eeSdp-arm 	va_list ap;
99819281eeSdp-arm 
100819281eeSdp-arm 	va_start(ap, msg);
101819281eeSdp-arm 	vlog(LOG_ERR, msg, ap);
102819281eeSdp-arm 	va_end(ap);
103819281eeSdp-arm 	exit(1);
104819281eeSdp-arm }
105819281eeSdp-arm 
106a22f6285Sdp-arm static char *xstrdup(const char *s, const char *msg)
107a22f6285Sdp-arm {
108a22f6285Sdp-arm 	char *d;
109a22f6285Sdp-arm 
110a22f6285Sdp-arm 	d = strdup(s);
111a22f6285Sdp-arm 	if (d == NULL)
1129fc9ff1fSdp-arm 		log_errx("strdup: %s", msg);
113a22f6285Sdp-arm 	return d;
114a22f6285Sdp-arm }
115a22f6285Sdp-arm 
116a22f6285Sdp-arm static void *xmalloc(size_t size, const char *msg)
117a22f6285Sdp-arm {
118a22f6285Sdp-arm 	void *d;
119a22f6285Sdp-arm 
120a22f6285Sdp-arm 	d = malloc(size);
121a22f6285Sdp-arm 	if (d == NULL)
1229fc9ff1fSdp-arm 		log_errx("malloc: %s", msg);
123a22f6285Sdp-arm 	return d;
124a22f6285Sdp-arm }
125a22f6285Sdp-arm 
126696ccba6SMasahiro Yamada static void *xzalloc(size_t size, const char *msg)
127696ccba6SMasahiro Yamada {
128696ccba6SMasahiro Yamada 	return memset(xmalloc(size, msg), 0, size);
129696ccba6SMasahiro Yamada }
130696ccba6SMasahiro Yamada 
131a1da83f5SMasahiro Yamada static void xfwrite(void *buf, size_t size, FILE *fp, const char *filename)
132a1da83f5SMasahiro Yamada {
133a1da83f5SMasahiro Yamada 	if (fwrite(buf, 1, size, fp) != size)
134a1da83f5SMasahiro Yamada 		log_errx("Failed to write %s", filename);
135a1da83f5SMasahiro Yamada }
136a1da83f5SMasahiro Yamada 
137e0f083a0Sdp-arm static image_desc_t *new_image_desc(const uuid_t *uuid,
138e0f083a0Sdp-arm     const char *name, const char *cmdline_name)
139e0f083a0Sdp-arm {
140e0f083a0Sdp-arm 	image_desc_t *desc;
141e0f083a0Sdp-arm 
142696ccba6SMasahiro Yamada 	desc = xzalloc(sizeof(*desc),
143e0f083a0Sdp-arm 	    "failed to allocate memory for image descriptor");
144e0f083a0Sdp-arm 	memcpy(&desc->uuid, uuid, sizeof(uuid_t));
145e0f083a0Sdp-arm 	desc->name = xstrdup(name,
146e0f083a0Sdp-arm 	    "failed to allocate memory for image name");
147e0f083a0Sdp-arm 	desc->cmdline_name = xstrdup(cmdline_name,
148e0f083a0Sdp-arm 	    "failed to allocate memory for image command line name");
149e0f083a0Sdp-arm 	desc->action = DO_UNSPEC;
150e0f083a0Sdp-arm 	return desc;
151e0f083a0Sdp-arm }
152e0f083a0Sdp-arm 
153d02fcebeSdp-arm static void set_image_desc_action(image_desc_t *desc, int action,
154d02fcebeSdp-arm     const char *arg)
155d02fcebeSdp-arm {
156d02fcebeSdp-arm 	assert(desc != NULL);
157d02fcebeSdp-arm 
15896851114SEvan Lloyd 	if (desc->action_arg != (char *)DO_UNSPEC)
159d02fcebeSdp-arm 		free(desc->action_arg);
160d02fcebeSdp-arm 	desc->action = action;
161d02fcebeSdp-arm 	desc->action_arg = NULL;
162d02fcebeSdp-arm 	if (arg != NULL)
163d02fcebeSdp-arm 		desc->action_arg = xstrdup(arg,
164d02fcebeSdp-arm 		    "failed to allocate memory for argument");
165d02fcebeSdp-arm }
166d02fcebeSdp-arm 
167e0f083a0Sdp-arm static void free_image_desc(image_desc_t *desc)
168e0f083a0Sdp-arm {
169e0f083a0Sdp-arm 	free(desc->name);
170e0f083a0Sdp-arm 	free(desc->cmdline_name);
171e0f083a0Sdp-arm 	free(desc->action_arg);
1728d283231SJonathan Wright 	if (desc->image) {
1738d283231SJonathan Wright 		free(desc->image->buffer);
174b9589fe5Sdp-arm 		free(desc->image);
1758d283231SJonathan Wright 	}
176e0f083a0Sdp-arm 	free(desc);
177e0f083a0Sdp-arm }
178e0f083a0Sdp-arm 
179e0f083a0Sdp-arm static void add_image_desc(image_desc_t *desc)
180e0f083a0Sdp-arm {
18111c0a4ffSMasahiro Yamada 	image_desc_t **p = &image_desc_head;
18211c0a4ffSMasahiro Yamada 
18311c0a4ffSMasahiro Yamada 	while (*p)
18411c0a4ffSMasahiro Yamada 		p = &(*p)->next;
18511c0a4ffSMasahiro Yamada 
186e9e0d287SMasahiro Yamada 	assert(*p == NULL);
18711c0a4ffSMasahiro Yamada 	*p = desc;
188e0f083a0Sdp-arm 	nr_image_descs++;
189e0f083a0Sdp-arm }
190e0f083a0Sdp-arm 
191e0f083a0Sdp-arm static void free_image_descs(void)
192e0f083a0Sdp-arm {
193e0f083a0Sdp-arm 	image_desc_t *desc = image_desc_head, *tmp;
194e0f083a0Sdp-arm 
195e0f083a0Sdp-arm 	while (desc != NULL) {
196e0f083a0Sdp-arm 		tmp = desc->next;
197e0f083a0Sdp-arm 		free_image_desc(desc);
198e0f083a0Sdp-arm 		desc = tmp;
199e0f083a0Sdp-arm 		nr_image_descs--;
200e0f083a0Sdp-arm 	}
201e0f083a0Sdp-arm 	assert(nr_image_descs == 0);
202e0f083a0Sdp-arm }
203e0f083a0Sdp-arm 
204e0f083a0Sdp-arm static void fill_image_descs(void)
205e0f083a0Sdp-arm {
206e0f083a0Sdp-arm 	toc_entry_t *toc_entry;
207e0f083a0Sdp-arm 
208e0f083a0Sdp-arm 	for (toc_entry = toc_entries;
209e0f083a0Sdp-arm 	     toc_entry->cmdline_name != NULL;
210e0f083a0Sdp-arm 	     toc_entry++) {
211e0f083a0Sdp-arm 		image_desc_t *desc;
212e0f083a0Sdp-arm 
213e0f083a0Sdp-arm 		desc = new_image_desc(&toc_entry->uuid,
214e0f083a0Sdp-arm 		    toc_entry->name,
215e0f083a0Sdp-arm 		    toc_entry->cmdline_name);
216e0f083a0Sdp-arm 		add_image_desc(desc);
217e0f083a0Sdp-arm 	}
2183527d6d2SPankaj Gupta #ifdef PLAT_DEF_FIP_UUID
2193527d6d2SPankaj Gupta 	for (toc_entry = plat_def_toc_entries;
2203527d6d2SPankaj Gupta 	     toc_entry->cmdline_name != NULL;
2213527d6d2SPankaj Gupta 	     toc_entry++) {
2223527d6d2SPankaj Gupta 		image_desc_t *desc;
2233527d6d2SPankaj Gupta 
2243527d6d2SPankaj Gupta 		desc = new_image_desc(&toc_entry->uuid,
2253527d6d2SPankaj Gupta 		    toc_entry->name,
2263527d6d2SPankaj Gupta 		    toc_entry->cmdline_name);
2273527d6d2SPankaj Gupta 		add_image_desc(desc);
2283527d6d2SPankaj Gupta 	}
2293527d6d2SPankaj Gupta #endif
230e0f083a0Sdp-arm }
231e0f083a0Sdp-arm 
232e0f083a0Sdp-arm static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid)
233819281eeSdp-arm {
234e0f083a0Sdp-arm 	image_desc_t *desc;
235819281eeSdp-arm 
236e0f083a0Sdp-arm 	for (desc = image_desc_head; desc != NULL; desc = desc->next)
237e0f083a0Sdp-arm 		if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
238e0f083a0Sdp-arm 			return desc;
239819281eeSdp-arm 	return NULL;
240819281eeSdp-arm }
241819281eeSdp-arm 
242e0f083a0Sdp-arm static image_desc_t *lookup_image_desc_from_opt(const char *opt)
243e0f083a0Sdp-arm {
244e0f083a0Sdp-arm 	image_desc_t *desc;
245e0f083a0Sdp-arm 
246e0f083a0Sdp-arm 	for (desc = image_desc_head; desc != NULL; desc = desc->next)
247e0f083a0Sdp-arm 		if (strcmp(desc->cmdline_name, opt) == 0)
248e0f083a0Sdp-arm 			return desc;
249e0f083a0Sdp-arm 	return NULL;
250e0f083a0Sdp-arm }
251e0f083a0Sdp-arm 
252fcab6bbeSdp-arm static void uuid_to_str(char *s, size_t len, const uuid_t *u)
253fcab6bbeSdp-arm {
254fcab6bbeSdp-arm 	assert(len >= (_UUID_STR_LEN + 1));
255fcab6bbeSdp-arm 
25603364865SRoberto Vargas 	snprintf(s, len,
25703364865SRoberto Vargas 	    "%02X%02X%02X%02X-%02X%02X-%02X%02X-%04X-%04X%04X%04X",
25803364865SRoberto Vargas 	    u->time_low[0], u->time_low[1], u->time_low[2], u->time_low[3],
25903364865SRoberto Vargas 	    u->time_mid[0], u->time_mid[1],
26003364865SRoberto Vargas 	    u->time_hi_and_version[0], u->time_hi_and_version[1],
26103364865SRoberto Vargas 	    (u->clock_seq_hi_and_reserved << 8) | u->clock_seq_low,
26203364865SRoberto Vargas 	    (u->node[0] << 8) | u->node[1],
26303364865SRoberto Vargas 	    (u->node[2] << 8) | u->node[3],
26403364865SRoberto Vargas 	    (u->node[4] << 8) | u->node[5]);
265fcab6bbeSdp-arm }
266fcab6bbeSdp-arm 
267fcab6bbeSdp-arm static void uuid_from_str(uuid_t *u, const char *s)
268fcab6bbeSdp-arm {
269fcab6bbeSdp-arm 	int n;
270fcab6bbeSdp-arm 
271fcab6bbeSdp-arm 	if (s == NULL)
272fcab6bbeSdp-arm 		log_errx("UUID cannot be NULL");
273fcab6bbeSdp-arm 	if (strlen(s) != _UUID_STR_LEN)
274fcab6bbeSdp-arm 		log_errx("Invalid UUID: %s", s);
275fcab6bbeSdp-arm 
276fcab6bbeSdp-arm 	n = sscanf(s,
27703364865SRoberto Vargas 	    "%2hhx%2hhx%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
27803364865SRoberto Vargas 	    &u->time_low[0], &u->time_low[1], &u->time_low[2], &u->time_low[3],
27903364865SRoberto Vargas 	    &u->time_mid[0], &u->time_mid[1],
28003364865SRoberto Vargas 	    &u->time_hi_and_version[0], &u->time_hi_and_version[1],
28103364865SRoberto Vargas 	    &u->clock_seq_hi_and_reserved, &u->clock_seq_low,
28203364865SRoberto Vargas 	    &u->node[0], &u->node[1],
28303364865SRoberto Vargas 	    &u->node[2], &u->node[3],
28403364865SRoberto Vargas 	    &u->node[4], &u->node[5]);
285fcab6bbeSdp-arm 	/*
286e56b8dc8SAndre Przywara 	 * Given the format specifier above, we expect 16 items to be scanned
287fcab6bbeSdp-arm 	 * for a properly formatted UUID.
288fcab6bbeSdp-arm 	 */
289e56b8dc8SAndre Przywara 	if (n != 16)
290fcab6bbeSdp-arm 		log_errx("Invalid UUID: %s", s);
291fcab6bbeSdp-arm }
292fcab6bbeSdp-arm 
29360b499feSdp-arm static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
294819281eeSdp-arm {
29596851114SEvan Lloyd 	struct BLD_PLAT_STAT st;
296819281eeSdp-arm 	FILE *fp;
297819281eeSdp-arm 	char *buf, *bufend;
298819281eeSdp-arm 	fip_toc_header_t *toc_header;
299819281eeSdp-arm 	fip_toc_entry_t *toc_entry;
300819281eeSdp-arm 	int terminated = 0;
301819281eeSdp-arm 
30255745deaSEvan Lloyd 	fp = fopen(filename, "rb");
303819281eeSdp-arm 	if (fp == NULL)
304819281eeSdp-arm 		log_err("fopen %s", filename);
305819281eeSdp-arm 
306819281eeSdp-arm 	if (fstat(fileno(fp), &st) == -1)
307819281eeSdp-arm 		log_err("fstat %s", filename);
308819281eeSdp-arm 
309a22f6285Sdp-arm 	buf = xmalloc(st.st_size, "failed to load file into memory");
310819281eeSdp-arm 	if (fread(buf, 1, st.st_size, fp) != st.st_size)
311819281eeSdp-arm 		log_errx("Failed to read %s", filename);
312819281eeSdp-arm 	bufend = buf + st.st_size;
313819281eeSdp-arm 	fclose(fp);
314819281eeSdp-arm 
315819281eeSdp-arm 	if (st.st_size < sizeof(fip_toc_header_t))
316819281eeSdp-arm 		log_errx("FIP %s is truncated", filename);
317819281eeSdp-arm 
318819281eeSdp-arm 	toc_header = (fip_toc_header_t *)buf;
319819281eeSdp-arm 	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
320819281eeSdp-arm 
321819281eeSdp-arm 	if (toc_header->name != TOC_HEADER_NAME)
322819281eeSdp-arm 		log_errx("%s is not a FIP file", filename);
323819281eeSdp-arm 
324819281eeSdp-arm 	/* Return the ToC header if the caller wants it. */
325819281eeSdp-arm 	if (toc_header_out != NULL)
326819281eeSdp-arm 		*toc_header_out = *toc_header;
327819281eeSdp-arm 
328819281eeSdp-arm 	/* Walk through each ToC entry in the file. */
329819281eeSdp-arm 	while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) {
330fcab6bbeSdp-arm 		image_t *image;
331fcab6bbeSdp-arm 		image_desc_t *desc;
332fcab6bbeSdp-arm 
333819281eeSdp-arm 		/* Found the ToC terminator, we are done. */
334819281eeSdp-arm 		if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) {
335819281eeSdp-arm 			terminated = 1;
336819281eeSdp-arm 			break;
337819281eeSdp-arm 		}
338819281eeSdp-arm 
339819281eeSdp-arm 		/*
340819281eeSdp-arm 		 * Build a new image out of the ToC entry and add it to the
341819281eeSdp-arm 		 * table of images.
342819281eeSdp-arm 		 */
34311c0a4ffSMasahiro Yamada 		image = xzalloc(sizeof(*image),
344a22f6285Sdp-arm 		    "failed to allocate memory for image");
34565caa3d0SMasahiro Yamada 		image->toc_e = *toc_entry;
346a22f6285Sdp-arm 		image->buffer = xmalloc(toc_entry->size,
347a22f6285Sdp-arm 		    "failed to allocate image buffer, is FIP file corrupted?");
348819281eeSdp-arm 		/* Overflow checks before memory copy. */
349819281eeSdp-arm 		if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address)
350819281eeSdp-arm 			log_errx("FIP %s is corrupted", filename);
351819281eeSdp-arm 		if (toc_entry->size + toc_entry->offset_address > st.st_size)
352819281eeSdp-arm 			log_errx("FIP %s is corrupted", filename);
353819281eeSdp-arm 
354819281eeSdp-arm 		memcpy(image->buffer, buf + toc_entry->offset_address,
355819281eeSdp-arm 		    toc_entry->size);
356819281eeSdp-arm 
357fcab6bbeSdp-arm 		/* If this is an unknown image, create a descriptor for it. */
35865caa3d0SMasahiro Yamada 		desc = lookup_image_desc_from_uuid(&toc_entry->uuid);
359fcab6bbeSdp-arm 		if (desc == NULL) {
360fcab6bbeSdp-arm 			char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
361fcab6bbeSdp-arm 
36265caa3d0SMasahiro Yamada 			uuid_to_str(name, sizeof(name), &toc_entry->uuid);
363fcab6bbeSdp-arm 			snprintf(filename, sizeof(filename), "%s%s",
364fcab6bbeSdp-arm 			    name, ".bin");
36565caa3d0SMasahiro Yamada 			desc = new_image_desc(&toc_entry->uuid, name, "blob");
366fcab6bbeSdp-arm 			desc->action = DO_UNPACK;
367fcab6bbeSdp-arm 			desc->action_arg = xstrdup(filename,
368fcab6bbeSdp-arm 			    "failed to allocate memory for blob filename");
369fcab6bbeSdp-arm 			add_image_desc(desc);
370fcab6bbeSdp-arm 		}
371fcab6bbeSdp-arm 
372b9589fe5Sdp-arm 		assert(desc->image == NULL);
373b9589fe5Sdp-arm 		desc->image = image;
374819281eeSdp-arm 
375819281eeSdp-arm 		toc_entry++;
376819281eeSdp-arm 	}
377819281eeSdp-arm 
378819281eeSdp-arm 	if (terminated == 0)
379819281eeSdp-arm 		log_errx("FIP %s does not have a ToC terminator entry",
380819281eeSdp-arm 		    filename);
381819281eeSdp-arm 	free(buf);
382819281eeSdp-arm 	return 0;
383819281eeSdp-arm }
384819281eeSdp-arm 
38560b499feSdp-arm static image_t *read_image_from_file(const uuid_t *uuid, const char *filename)
386819281eeSdp-arm {
38796851114SEvan Lloyd 	struct BLD_PLAT_STAT st;
388819281eeSdp-arm 	image_t *image;
389819281eeSdp-arm 	FILE *fp;
390819281eeSdp-arm 
391b04efcceSdp-arm 	assert(uuid != NULL);
39296851114SEvan Lloyd 	assert(filename != NULL);
393b04efcceSdp-arm 
39455745deaSEvan Lloyd 	fp = fopen(filename, "rb");
395819281eeSdp-arm 	if (fp == NULL)
396819281eeSdp-arm 		log_err("fopen %s", filename);
397819281eeSdp-arm 
398819281eeSdp-arm 	if (fstat(fileno(fp), &st) == -1)
399819281eeSdp-arm 		log_errx("fstat %s", filename);
400819281eeSdp-arm 
40111c0a4ffSMasahiro Yamada 	image = xzalloc(sizeof(*image), "failed to allocate memory for image");
40265caa3d0SMasahiro Yamada 	image->toc_e.uuid = *uuid;
403a22f6285Sdp-arm 	image->buffer = xmalloc(st.st_size, "failed to allocate image buffer");
404819281eeSdp-arm 	if (fread(image->buffer, 1, st.st_size, fp) != st.st_size)
405819281eeSdp-arm 		log_errx("Failed to read %s", filename);
40665caa3d0SMasahiro Yamada 	image->toc_e.size = st.st_size;
407819281eeSdp-arm 
408819281eeSdp-arm 	fclose(fp);
409819281eeSdp-arm 	return image;
410819281eeSdp-arm }
411819281eeSdp-arm 
41260b499feSdp-arm static int write_image_to_file(const image_t *image, const char *filename)
413819281eeSdp-arm {
414819281eeSdp-arm 	FILE *fp;
415819281eeSdp-arm 
41655745deaSEvan Lloyd 	fp = fopen(filename, "wb");
417819281eeSdp-arm 	if (fp == NULL)
418819281eeSdp-arm 		log_err("fopen");
41965caa3d0SMasahiro Yamada 	xfwrite(image->buffer, image->toc_e.size, fp, filename);
420819281eeSdp-arm 	fclose(fp);
421819281eeSdp-arm 	return 0;
422819281eeSdp-arm }
423819281eeSdp-arm 
424e0f083a0Sdp-arm static struct option *add_opt(struct option *opts, size_t *nr_opts,
425e0f083a0Sdp-arm     const char *name, int has_arg, int val)
426819281eeSdp-arm {
427e0f083a0Sdp-arm 	opts = realloc(opts, (*nr_opts + 1) * sizeof(*opts));
428e0f083a0Sdp-arm 	if (opts == NULL)
429e0f083a0Sdp-arm 		log_err("realloc");
430e0f083a0Sdp-arm 	opts[*nr_opts].name = name;
431e0f083a0Sdp-arm 	opts[*nr_opts].has_arg = has_arg;
432e0f083a0Sdp-arm 	opts[*nr_opts].flag = NULL;
433e0f083a0Sdp-arm 	opts[*nr_opts].val = val;
434e0f083a0Sdp-arm 	++*nr_opts;
435e0f083a0Sdp-arm 	return opts;
436819281eeSdp-arm }
437819281eeSdp-arm 
438e0f083a0Sdp-arm static struct option *fill_common_opts(struct option *opts, size_t *nr_opts,
439e0f083a0Sdp-arm     int has_arg)
440819281eeSdp-arm {
441e0f083a0Sdp-arm 	image_desc_t *desc;
442e0f083a0Sdp-arm 
443e0f083a0Sdp-arm 	for (desc = image_desc_head; desc != NULL; desc = desc->next)
444e0f083a0Sdp-arm 		opts = add_opt(opts, nr_opts, desc->cmdline_name, has_arg,
445e0f083a0Sdp-arm 		    OPT_TOC_ENTRY);
446e0f083a0Sdp-arm 	return opts;
447819281eeSdp-arm }
448819281eeSdp-arm 
449e0f083a0Sdp-arm static void md_print(const unsigned char *md, size_t len)
4509df69ba3Sdp-arm {
4519df69ba3Sdp-arm 	size_t i;
4529df69ba3Sdp-arm 
4539df69ba3Sdp-arm 	for (i = 0; i < len; i++)
4549df69ba3Sdp-arm 		printf("%02x", md[i]);
4559df69ba3Sdp-arm }
4569df69ba3Sdp-arm 
457819281eeSdp-arm static int info_cmd(int argc, char *argv[])
458819281eeSdp-arm {
459b9589fe5Sdp-arm 	image_desc_t *desc;
460819281eeSdp-arm 	fip_toc_header_t toc_header;
461819281eeSdp-arm 
462819281eeSdp-arm 	if (argc != 2)
4634e500525SLeonardo Sandoval 		info_usage(EXIT_FAILURE);
464819281eeSdp-arm 	argc--, argv++;
465819281eeSdp-arm 
466819281eeSdp-arm 	parse_fip(argv[0], &toc_header);
467819281eeSdp-arm 
468819281eeSdp-arm 	if (verbose) {
469819281eeSdp-arm 		log_dbgx("toc_header[name]: 0x%llX",
470819281eeSdp-arm 		    (unsigned long long)toc_header.name);
471819281eeSdp-arm 		log_dbgx("toc_header[serial_number]: 0x%llX",
472819281eeSdp-arm 		    (unsigned long long)toc_header.serial_number);
473819281eeSdp-arm 		log_dbgx("toc_header[flags]: 0x%llX",
474819281eeSdp-arm 		    (unsigned long long)toc_header.flags);
475819281eeSdp-arm 	}
476819281eeSdp-arm 
477b9589fe5Sdp-arm 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
478b9589fe5Sdp-arm 		image_t *image = desc->image;
479b04efcceSdp-arm 
480b9589fe5Sdp-arm 		if (image == NULL)
481b9589fe5Sdp-arm 			continue;
48265caa3d0SMasahiro Yamada 		printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"--%s\"",
48365caa3d0SMasahiro Yamada 		       desc->name,
48465caa3d0SMasahiro Yamada 		       (unsigned long long)image->toc_e.offset_address,
48565caa3d0SMasahiro Yamada 		       (unsigned long long)image->toc_e.size,
486e0f083a0Sdp-arm 		       desc->cmdline_name);
48796851114SEvan Lloyd #ifndef _MSC_VER	/* We don't have SHA256 for Visual Studio. */
4889df69ba3Sdp-arm 		if (verbose) {
4899df69ba3Sdp-arm 			unsigned char md[SHA256_DIGEST_LENGTH];
4909df69ba3Sdp-arm 
49165caa3d0SMasahiro Yamada 			SHA256(image->buffer, image->toc_e.size, md);
4929df69ba3Sdp-arm 			printf(", sha256=");
4939df69ba3Sdp-arm 			md_print(md, sizeof(md));
4949df69ba3Sdp-arm 		}
49596851114SEvan Lloyd #endif
496819281eeSdp-arm 		putchar('\n');
497819281eeSdp-arm 	}
498819281eeSdp-arm 
499819281eeSdp-arm 	return 0;
500819281eeSdp-arm }
501819281eeSdp-arm 
5024e500525SLeonardo Sandoval static void info_usage(int exit_status)
503819281eeSdp-arm {
504819281eeSdp-arm 	printf("fiptool info FIP_FILENAME\n");
5054e500525SLeonardo Sandoval 	exit(exit_status);
506819281eeSdp-arm }
507819281eeSdp-arm 
5081c75d5dfSMasahiro Yamada static int pack_images(const char *filename, uint64_t toc_flags, unsigned long align)
509819281eeSdp-arm {
510819281eeSdp-arm 	FILE *fp;
511b9589fe5Sdp-arm 	image_desc_t *desc;
512819281eeSdp-arm 	fip_toc_header_t *toc_header;
513819281eeSdp-arm 	fip_toc_entry_t *toc_entry;
514819281eeSdp-arm 	char *buf;
515880b9e8bSRoberto Vargas 	uint64_t entry_offset, buf_size, payload_size = 0, pad_size;
516b9589fe5Sdp-arm 	size_t nr_images = 0;
517b9589fe5Sdp-arm 
518b9589fe5Sdp-arm 	for (desc = image_desc_head; desc != NULL; desc = desc->next)
519b9589fe5Sdp-arm 		if (desc->image != NULL)
520b9589fe5Sdp-arm 			nr_images++;
521819281eeSdp-arm 
522819281eeSdp-arm 	buf_size = sizeof(fip_toc_header_t) +
523819281eeSdp-arm 	    sizeof(fip_toc_entry_t) * (nr_images + 1);
524819281eeSdp-arm 	buf = calloc(1, buf_size);
525819281eeSdp-arm 	if (buf == NULL)
526819281eeSdp-arm 		log_err("calloc");
527819281eeSdp-arm 
528819281eeSdp-arm 	/* Build up header and ToC entries from the image table. */
529819281eeSdp-arm 	toc_header = (fip_toc_header_t *)buf;
530819281eeSdp-arm 	toc_header->name = TOC_HEADER_NAME;
531819281eeSdp-arm 	toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
532819281eeSdp-arm 	toc_header->flags = toc_flags;
533819281eeSdp-arm 
534819281eeSdp-arm 	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
535819281eeSdp-arm 
536819281eeSdp-arm 	entry_offset = buf_size;
537b9589fe5Sdp-arm 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
538b9589fe5Sdp-arm 		image_t *image = desc->image;
539b9589fe5Sdp-arm 
540*ab556c9cSManish V Badarkhe 		if (image == NULL || (image->toc_e.size == 0ULL))
541b9589fe5Sdp-arm 			continue;
54265caa3d0SMasahiro Yamada 		payload_size += image->toc_e.size;
5431c75d5dfSMasahiro Yamada 		entry_offset = (entry_offset + align - 1) & ~(align - 1);
54465caa3d0SMasahiro Yamada 		image->toc_e.offset_address = entry_offset;
54565caa3d0SMasahiro Yamada 		*toc_entry++ = image->toc_e;
54665caa3d0SMasahiro Yamada 		entry_offset += image->toc_e.size;
547819281eeSdp-arm 	}
548819281eeSdp-arm 
549880b9e8bSRoberto Vargas 	/*
550880b9e8bSRoberto Vargas 	 * Append a null uuid entry to mark the end of ToC entries.
551880b9e8bSRoberto Vargas 	 * NOTE the offset address for the last toc_entry must match the fip
552880b9e8bSRoberto Vargas 	 * size.
553880b9e8bSRoberto Vargas 	 */
55465caa3d0SMasahiro Yamada 	memset(toc_entry, 0, sizeof(*toc_entry));
555880b9e8bSRoberto Vargas 	toc_entry->offset_address = (entry_offset + align - 1) & ~(align - 1);
556819281eeSdp-arm 
557819281eeSdp-arm 	/* Generate the FIP file. */
55855745deaSEvan Lloyd 	fp = fopen(filename, "wb");
559819281eeSdp-arm 	if (fp == NULL)
560819281eeSdp-arm 		log_err("fopen %s", filename);
561819281eeSdp-arm 
562819281eeSdp-arm 	if (verbose)
563819281eeSdp-arm 		log_dbgx("Metadata size: %zu bytes", buf_size);
564819281eeSdp-arm 
565a1da83f5SMasahiro Yamada 	xfwrite(buf, buf_size, fp, filename);
566819281eeSdp-arm 
567819281eeSdp-arm 	if (verbose)
568819281eeSdp-arm 		log_dbgx("Payload size: %zu bytes", payload_size);
569819281eeSdp-arm 
570b9589fe5Sdp-arm 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
571b9589fe5Sdp-arm 		image_t *image = desc->image;
572b9589fe5Sdp-arm 
573b9589fe5Sdp-arm 		if (image == NULL)
574b9589fe5Sdp-arm 			continue;
5751c75d5dfSMasahiro Yamada 		if (fseek(fp, image->toc_e.offset_address, SEEK_SET))
5761c75d5dfSMasahiro Yamada 			log_errx("Failed to set file position");
5771c75d5dfSMasahiro Yamada 
57865caa3d0SMasahiro Yamada 		xfwrite(image->buffer, image->toc_e.size, fp, filename);
5791c75d5dfSMasahiro Yamada 	}
580819281eeSdp-arm 
581880b9e8bSRoberto Vargas 	if (fseek(fp, entry_offset, SEEK_SET))
582880b9e8bSRoberto Vargas 		log_errx("Failed to set file position");
583880b9e8bSRoberto Vargas 
584880b9e8bSRoberto Vargas 	pad_size = toc_entry->offset_address - entry_offset;
585880b9e8bSRoberto Vargas 	while (pad_size--)
586880b9e8bSRoberto Vargas 		fputc(0x0, fp);
587880b9e8bSRoberto Vargas 
5888e4cdd22SAndreas Färber 	free(buf);
589819281eeSdp-arm 	fclose(fp);
590819281eeSdp-arm 	return 0;
591819281eeSdp-arm }
592819281eeSdp-arm 
593819281eeSdp-arm /*
594819281eeSdp-arm  * This function is shared between the create and update subcommands.
595819281eeSdp-arm  * The difference between the two subcommands is that when the FIP file
596819281eeSdp-arm  * is created, the parsing of an existing FIP is skipped.  This results
597819281eeSdp-arm  * in update_fip() creating the new FIP file from scratch because the
598819281eeSdp-arm  * internal image table is not populated.
599819281eeSdp-arm  */
600819281eeSdp-arm static void update_fip(void)
601819281eeSdp-arm {
602e0f083a0Sdp-arm 	image_desc_t *desc;
603819281eeSdp-arm 
604819281eeSdp-arm 	/* Add or replace images in the FIP file. */
605e0f083a0Sdp-arm 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
606b9589fe5Sdp-arm 		image_t *image;
607fcab6bbeSdp-arm 
608e0f083a0Sdp-arm 		if (desc->action != DO_PACK)
609819281eeSdp-arm 			continue;
610819281eeSdp-arm 
611b9589fe5Sdp-arm 		image = read_image_from_file(&desc->uuid,
612e0f083a0Sdp-arm 		    desc->action_arg);
613b9589fe5Sdp-arm 		if (desc->image != NULL) {
614e0f083a0Sdp-arm 			if (verbose) {
615fcab6bbeSdp-arm 				log_dbgx("Replacing %s with %s",
616e0f083a0Sdp-arm 				    desc->cmdline_name,
617e0f083a0Sdp-arm 				    desc->action_arg);
618e0f083a0Sdp-arm 			}
619b9589fe5Sdp-arm 			free(desc->image);
620b9589fe5Sdp-arm 			desc->image = image;
621819281eeSdp-arm 		} else {
622819281eeSdp-arm 			if (verbose)
623819281eeSdp-arm 				log_dbgx("Adding image %s",
624e0f083a0Sdp-arm 				    desc->action_arg);
625b9589fe5Sdp-arm 			desc->image = image;
626819281eeSdp-arm 		}
627819281eeSdp-arm 	}
628819281eeSdp-arm }
629819281eeSdp-arm 
630e0f083a0Sdp-arm static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags)
631819281eeSdp-arm {
632819281eeSdp-arm 	unsigned long long flags;
633819281eeSdp-arm 	char *endptr;
634819281eeSdp-arm 
635819281eeSdp-arm 	errno = 0;
636819281eeSdp-arm 	flags = strtoull(arg, &endptr, 16);
637819281eeSdp-arm 	if (*endptr != '\0' || flags > UINT16_MAX || errno != 0)
638819281eeSdp-arm 		log_errx("Invalid platform ToC flags: %s", arg);
639819281eeSdp-arm 	/* Platform ToC flags is a 16-bit field occupying bits [32-47]. */
640819281eeSdp-arm 	*toc_flags |= flags << 32;
641819281eeSdp-arm }
642819281eeSdp-arm 
6431c75d5dfSMasahiro Yamada static int is_power_of_2(unsigned long x)
6441c75d5dfSMasahiro Yamada {
6451c75d5dfSMasahiro Yamada 	return x && !(x & (x - 1));
6461c75d5dfSMasahiro Yamada }
6471c75d5dfSMasahiro Yamada 
6481c75d5dfSMasahiro Yamada static unsigned long get_image_align(char *arg)
6491c75d5dfSMasahiro Yamada {
6501c75d5dfSMasahiro Yamada 	char *endptr;
6511c75d5dfSMasahiro Yamada 	unsigned long align;
6521c75d5dfSMasahiro Yamada 
6531c75d5dfSMasahiro Yamada 	errno = 0;
654fb5f7949SAndreas Färber 	align = strtoul(arg, &endptr, 0);
6551c75d5dfSMasahiro Yamada 	if (*endptr != '\0' || !is_power_of_2(align) || errno != 0)
6561c75d5dfSMasahiro Yamada 		log_errx("Invalid alignment: %s", arg);
6571c75d5dfSMasahiro Yamada 
6581c75d5dfSMasahiro Yamada 	return align;
6591c75d5dfSMasahiro Yamada }
6601c75d5dfSMasahiro Yamada 
661fcab6bbeSdp-arm static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len)
662fcab6bbeSdp-arm {
663fcab6bbeSdp-arm 	char *p;
664fcab6bbeSdp-arm 
665fcab6bbeSdp-arm 	for (p = strtok(arg, ","); p != NULL; p = strtok(NULL, ",")) {
666fcab6bbeSdp-arm 		if (strncmp(p, "uuid=", strlen("uuid=")) == 0) {
667fcab6bbeSdp-arm 			p += strlen("uuid=");
668fcab6bbeSdp-arm 			uuid_from_str(uuid, p);
669fcab6bbeSdp-arm 		} else if (strncmp(p, "file=", strlen("file=")) == 0) {
670fcab6bbeSdp-arm 			p += strlen("file=");
671fcab6bbeSdp-arm 			snprintf(filename, len, "%s", p);
672fcab6bbeSdp-arm 		}
673fcab6bbeSdp-arm 	}
674fcab6bbeSdp-arm }
675fcab6bbeSdp-arm 
676819281eeSdp-arm static int create_cmd(int argc, char *argv[])
677819281eeSdp-arm {
678e0f083a0Sdp-arm 	struct option *opts = NULL;
679e0f083a0Sdp-arm 	size_t nr_opts = 0;
680819281eeSdp-arm 	unsigned long long toc_flags = 0;
6811c75d5dfSMasahiro Yamada 	unsigned long align = 1;
682819281eeSdp-arm 
683819281eeSdp-arm 	if (argc < 2)
6844e500525SLeonardo Sandoval 		create_usage(EXIT_FAILURE);
685819281eeSdp-arm 
686e0f083a0Sdp-arm 	opts = fill_common_opts(opts, &nr_opts, required_argument);
687e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
688819281eeSdp-arm 	    OPT_PLAT_TOC_FLAGS);
6891c75d5dfSMasahiro Yamada 	opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
690fcab6bbeSdp-arm 	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
691e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
692819281eeSdp-arm 
693819281eeSdp-arm 	while (1) {
69420f87e78Sdp-arm 		int c, opt_index = 0;
695819281eeSdp-arm 
696fcab6bbeSdp-arm 		c = getopt_long(argc, argv, "b:", opts, &opt_index);
697819281eeSdp-arm 		if (c == -1)
698819281eeSdp-arm 			break;
699819281eeSdp-arm 
700819281eeSdp-arm 		switch (c) {
701819281eeSdp-arm 		case OPT_TOC_ENTRY: {
702e0f083a0Sdp-arm 			image_desc_t *desc;
703819281eeSdp-arm 
704e0f083a0Sdp-arm 			desc = lookup_image_desc_from_opt(opts[opt_index].name);
705d02fcebeSdp-arm 			set_image_desc_action(desc, DO_PACK, optarg);
706819281eeSdp-arm 			break;
707819281eeSdp-arm 		}
708819281eeSdp-arm 		case OPT_PLAT_TOC_FLAGS:
709819281eeSdp-arm 			parse_plat_toc_flags(optarg, &toc_flags);
710819281eeSdp-arm 			break;
7111c75d5dfSMasahiro Yamada 		case OPT_ALIGN:
7121c75d5dfSMasahiro Yamada 			align = get_image_align(optarg);
7131c75d5dfSMasahiro Yamada 			break;
714fcab6bbeSdp-arm 		case 'b': {
715fcab6bbeSdp-arm 			char name[_UUID_STR_LEN + 1];
716fcab6bbeSdp-arm 			char filename[PATH_MAX] = { 0 };
71703364865SRoberto Vargas 			uuid_t uuid = uuid_null;
718fcab6bbeSdp-arm 			image_desc_t *desc;
719fcab6bbeSdp-arm 
720fcab6bbeSdp-arm 			parse_blob_opt(optarg, &uuid,
721fcab6bbeSdp-arm 			    filename, sizeof(filename));
722fcab6bbeSdp-arm 
723fcab6bbeSdp-arm 			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
724fcab6bbeSdp-arm 			    filename[0] == '\0')
7254e500525SLeonardo Sandoval 				create_usage(EXIT_FAILURE);
726fcab6bbeSdp-arm 
727fcab6bbeSdp-arm 			desc = lookup_image_desc_from_uuid(&uuid);
728d02fcebeSdp-arm 			if (desc == NULL) {
729fcab6bbeSdp-arm 				uuid_to_str(name, sizeof(name), &uuid);
730fcab6bbeSdp-arm 				desc = new_image_desc(&uuid, name, "blob");
731fcab6bbeSdp-arm 				add_image_desc(desc);
732fcab6bbeSdp-arm 			}
733d02fcebeSdp-arm 			set_image_desc_action(desc, DO_PACK, filename);
734fcab6bbeSdp-arm 			break;
735fcab6bbeSdp-arm 		}
736819281eeSdp-arm 		default:
7374e500525SLeonardo Sandoval 			create_usage(EXIT_FAILURE);
738819281eeSdp-arm 		}
739819281eeSdp-arm 	}
740819281eeSdp-arm 	argc -= optind;
741819281eeSdp-arm 	argv += optind;
742e0f083a0Sdp-arm 	free(opts);
743819281eeSdp-arm 
744819281eeSdp-arm 	if (argc == 0)
7454e500525SLeonardo Sandoval 		create_usage(EXIT_SUCCESS);
746819281eeSdp-arm 
747819281eeSdp-arm 	update_fip();
748819281eeSdp-arm 
7491c75d5dfSMasahiro Yamada 	pack_images(argv[0], toc_flags, align);
750819281eeSdp-arm 	return 0;
751819281eeSdp-arm }
752819281eeSdp-arm 
7534e500525SLeonardo Sandoval static void create_usage(int exit_status)
754819281eeSdp-arm {
755819281eeSdp-arm 	toc_entry_t *toc_entry = toc_entries;
756819281eeSdp-arm 
757ee079320SMasahiro Yamada 	printf("fiptool create [opts] FIP_FILENAME\n");
758ee079320SMasahiro Yamada 	printf("\n");
759ee079320SMasahiro Yamada 	printf("Options:\n");
7601c75d5dfSMasahiro Yamada 	printf("  --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
761802b42a0SMasahiro Yamada 	printf("  --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n");
762802b42a0SMasahiro Yamada 	printf("  --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
76395d2b268SMasahiro Yamada 	printf("\n");
764819281eeSdp-arm 	printf("Specific images are packed with the following options:\n");
765819281eeSdp-arm 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
766819281eeSdp-arm 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
767819281eeSdp-arm 		    toc_entry->name);
7683527d6d2SPankaj Gupta #ifdef PLAT_DEF_FIP_UUID
7693527d6d2SPankaj Gupta 	toc_entry = plat_def_toc_entries;
7703527d6d2SPankaj Gupta 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
7713527d6d2SPankaj Gupta 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
7723527d6d2SPankaj Gupta 		    toc_entry->name);
7733527d6d2SPankaj Gupta #endif
7744e500525SLeonardo Sandoval 	exit(exit_status);
775819281eeSdp-arm }
776819281eeSdp-arm 
777819281eeSdp-arm static int update_cmd(int argc, char *argv[])
778819281eeSdp-arm {
779e0f083a0Sdp-arm 	struct option *opts = NULL;
780e0f083a0Sdp-arm 	size_t nr_opts = 0;
781fcab6bbeSdp-arm 	char outfile[PATH_MAX] = { 0 };
782819281eeSdp-arm 	fip_toc_header_t toc_header = { 0 };
783819281eeSdp-arm 	unsigned long long toc_flags = 0;
7841c75d5dfSMasahiro Yamada 	unsigned long align = 1;
785819281eeSdp-arm 	int pflag = 0;
786819281eeSdp-arm 
787819281eeSdp-arm 	if (argc < 2)
7884e500525SLeonardo Sandoval 		update_usage(EXIT_FAILURE);
789819281eeSdp-arm 
790e0f083a0Sdp-arm 	opts = fill_common_opts(opts, &nr_opts, required_argument);
7911c75d5dfSMasahiro Yamada 	opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
792fcab6bbeSdp-arm 	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
793e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
794e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
795819281eeSdp-arm 	    OPT_PLAT_TOC_FLAGS);
796e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
797819281eeSdp-arm 
798819281eeSdp-arm 	while (1) {
79920f87e78Sdp-arm 		int c, opt_index = 0;
800819281eeSdp-arm 
801fcab6bbeSdp-arm 		c = getopt_long(argc, argv, "b:o:", opts, &opt_index);
802819281eeSdp-arm 		if (c == -1)
803819281eeSdp-arm 			break;
804819281eeSdp-arm 
805819281eeSdp-arm 		switch (c) {
806819281eeSdp-arm 		case OPT_TOC_ENTRY: {
807e0f083a0Sdp-arm 			image_desc_t *desc;
808819281eeSdp-arm 
809e0f083a0Sdp-arm 			desc = lookup_image_desc_from_opt(opts[opt_index].name);
810d02fcebeSdp-arm 			set_image_desc_action(desc, DO_PACK, optarg);
811819281eeSdp-arm 			break;
812819281eeSdp-arm 		}
813e0f083a0Sdp-arm 		case OPT_PLAT_TOC_FLAGS:
814819281eeSdp-arm 			parse_plat_toc_flags(optarg, &toc_flags);
815819281eeSdp-arm 			pflag = 1;
816819281eeSdp-arm 			break;
817fcab6bbeSdp-arm 		case 'b': {
818fcab6bbeSdp-arm 			char name[_UUID_STR_LEN + 1];
819fcab6bbeSdp-arm 			char filename[PATH_MAX] = { 0 };
82003364865SRoberto Vargas 			uuid_t uuid = uuid_null;
821fcab6bbeSdp-arm 			image_desc_t *desc;
822fcab6bbeSdp-arm 
823fcab6bbeSdp-arm 			parse_blob_opt(optarg, &uuid,
824fcab6bbeSdp-arm 			    filename, sizeof(filename));
825fcab6bbeSdp-arm 
826fcab6bbeSdp-arm 			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
827fcab6bbeSdp-arm 			    filename[0] == '\0')
8284e500525SLeonardo Sandoval 				update_usage(EXIT_FAILURE);
829fcab6bbeSdp-arm 
830fcab6bbeSdp-arm 			desc = lookup_image_desc_from_uuid(&uuid);
831d02fcebeSdp-arm 			if (desc == NULL) {
832fcab6bbeSdp-arm 				uuid_to_str(name, sizeof(name), &uuid);
833fcab6bbeSdp-arm 				desc = new_image_desc(&uuid, name, "blob");
834fcab6bbeSdp-arm 				add_image_desc(desc);
835fcab6bbeSdp-arm 			}
836d02fcebeSdp-arm 			set_image_desc_action(desc, DO_PACK, filename);
837fcab6bbeSdp-arm 			break;
838fcab6bbeSdp-arm 		}
8391c75d5dfSMasahiro Yamada 		case OPT_ALIGN:
8401c75d5dfSMasahiro Yamada 			align = get_image_align(optarg);
8411c75d5dfSMasahiro Yamada 			break;
842819281eeSdp-arm 		case 'o':
843819281eeSdp-arm 			snprintf(outfile, sizeof(outfile), "%s", optarg);
844819281eeSdp-arm 			break;
845819281eeSdp-arm 		default:
8464e500525SLeonardo Sandoval 			update_usage(EXIT_FAILURE);
847819281eeSdp-arm 		}
848819281eeSdp-arm 	}
849819281eeSdp-arm 	argc -= optind;
850819281eeSdp-arm 	argv += optind;
851e0f083a0Sdp-arm 	free(opts);
852819281eeSdp-arm 
853819281eeSdp-arm 	if (argc == 0)
8544e500525SLeonardo Sandoval 		update_usage(EXIT_SUCCESS);
855819281eeSdp-arm 
856819281eeSdp-arm 	if (outfile[0] == '\0')
857819281eeSdp-arm 		snprintf(outfile, sizeof(outfile), "%s", argv[0]);
858819281eeSdp-arm 
85940866aafSMasahiro Yamada 	if (access(argv[0], F_OK) == 0)
860819281eeSdp-arm 		parse_fip(argv[0], &toc_header);
861819281eeSdp-arm 
862819281eeSdp-arm 	if (pflag)
863819281eeSdp-arm 		toc_header.flags &= ~(0xffffULL << 32);
864819281eeSdp-arm 	toc_flags = (toc_header.flags |= toc_flags);
865819281eeSdp-arm 
866819281eeSdp-arm 	update_fip();
867819281eeSdp-arm 
8681c75d5dfSMasahiro Yamada 	pack_images(outfile, toc_flags, align);
869819281eeSdp-arm 	return 0;
870819281eeSdp-arm }
871819281eeSdp-arm 
8724e500525SLeonardo Sandoval static void update_usage(int exit_status)
873819281eeSdp-arm {
874819281eeSdp-arm 	toc_entry_t *toc_entry = toc_entries;
875819281eeSdp-arm 
876ee079320SMasahiro Yamada 	printf("fiptool update [opts] FIP_FILENAME\n");
877ee079320SMasahiro Yamada 	printf("\n");
878ee079320SMasahiro Yamada 	printf("Options:\n");
8791c75d5dfSMasahiro Yamada 	printf("  --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
880802b42a0SMasahiro Yamada 	printf("  --blob uuid=...,file=...\tAdd or update an image with the given UUID pointed to by file.\n");
881819281eeSdp-arm 	printf("  --out FIP_FILENAME\t\tSet an alternative output FIP file.\n");
882802b42a0SMasahiro Yamada 	printf("  --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
88395d2b268SMasahiro Yamada 	printf("\n");
884819281eeSdp-arm 	printf("Specific images are packed with the following options:\n");
885819281eeSdp-arm 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
886819281eeSdp-arm 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
887819281eeSdp-arm 		    toc_entry->name);
8883527d6d2SPankaj Gupta #ifdef PLAT_DEF_FIP_UUID
8893527d6d2SPankaj Gupta 	toc_entry = plat_def_toc_entries;
8903527d6d2SPankaj Gupta 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
8913527d6d2SPankaj Gupta 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
8923527d6d2SPankaj Gupta 		    toc_entry->name);
8933527d6d2SPankaj Gupta #endif
8944e500525SLeonardo Sandoval 	exit(exit_status);
895819281eeSdp-arm }
896819281eeSdp-arm 
897819281eeSdp-arm static int unpack_cmd(int argc, char *argv[])
898819281eeSdp-arm {
899e0f083a0Sdp-arm 	struct option *opts = NULL;
900e0f083a0Sdp-arm 	size_t nr_opts = 0;
901fcab6bbeSdp-arm 	char outdir[PATH_MAX] = { 0 };
902e0f083a0Sdp-arm 	image_desc_t *desc;
903819281eeSdp-arm 	int fflag = 0;
904819281eeSdp-arm 	int unpack_all = 1;
905819281eeSdp-arm 
906819281eeSdp-arm 	if (argc < 2)
9074e500525SLeonardo Sandoval 		unpack_usage(EXIT_FAILURE);
908819281eeSdp-arm 
909e0f083a0Sdp-arm 	opts = fill_common_opts(opts, &nr_opts, required_argument);
910fcab6bbeSdp-arm 	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
911e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
912e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
913e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
914819281eeSdp-arm 
915819281eeSdp-arm 	while (1) {
91620f87e78Sdp-arm 		int c, opt_index = 0;
917819281eeSdp-arm 
918fcab6bbeSdp-arm 		c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
919819281eeSdp-arm 		if (c == -1)
920819281eeSdp-arm 			break;
921819281eeSdp-arm 
922819281eeSdp-arm 		switch (c) {
923e0f083a0Sdp-arm 		case OPT_TOC_ENTRY: {
924e0f083a0Sdp-arm 			image_desc_t *desc;
925e0f083a0Sdp-arm 
926e0f083a0Sdp-arm 			desc = lookup_image_desc_from_opt(opts[opt_index].name);
927d02fcebeSdp-arm 			set_image_desc_action(desc, DO_UNPACK, optarg);
928e0f083a0Sdp-arm 			unpack_all = 0;
929819281eeSdp-arm 			break;
930e0f083a0Sdp-arm 		}
931fcab6bbeSdp-arm 		case 'b': {
932fcab6bbeSdp-arm 			char name[_UUID_STR_LEN + 1];
933fcab6bbeSdp-arm 			char filename[PATH_MAX] = { 0 };
93403364865SRoberto Vargas 			uuid_t uuid = uuid_null;
935fcab6bbeSdp-arm 			image_desc_t *desc;
936fcab6bbeSdp-arm 
937fcab6bbeSdp-arm 			parse_blob_opt(optarg, &uuid,
938fcab6bbeSdp-arm 			    filename, sizeof(filename));
939fcab6bbeSdp-arm 
940fcab6bbeSdp-arm 			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
941fcab6bbeSdp-arm 			    filename[0] == '\0')
9424e500525SLeonardo Sandoval 				unpack_usage(EXIT_FAILURE);
943fcab6bbeSdp-arm 
944fcab6bbeSdp-arm 			desc = lookup_image_desc_from_uuid(&uuid);
945d02fcebeSdp-arm 			if (desc == NULL) {
946fcab6bbeSdp-arm 				uuid_to_str(name, sizeof(name), &uuid);
947fcab6bbeSdp-arm 				desc = new_image_desc(&uuid, name, "blob");
948fcab6bbeSdp-arm 				add_image_desc(desc);
949fcab6bbeSdp-arm 			}
950d02fcebeSdp-arm 			set_image_desc_action(desc, DO_UNPACK, filename);
951fcab6bbeSdp-arm 			unpack_all = 0;
952fcab6bbeSdp-arm 			break;
953fcab6bbeSdp-arm 		}
954819281eeSdp-arm 		case 'f':
955819281eeSdp-arm 			fflag = 1;
956819281eeSdp-arm 			break;
957819281eeSdp-arm 		case 'o':
958819281eeSdp-arm 			snprintf(outdir, sizeof(outdir), "%s", optarg);
959819281eeSdp-arm 			break;
960819281eeSdp-arm 		default:
9614e500525SLeonardo Sandoval 			unpack_usage(EXIT_FAILURE);
962819281eeSdp-arm 		}
963819281eeSdp-arm 	}
964819281eeSdp-arm 	argc -= optind;
965819281eeSdp-arm 	argv += optind;
966e0f083a0Sdp-arm 	free(opts);
967819281eeSdp-arm 
968819281eeSdp-arm 	if (argc == 0)
9694e500525SLeonardo Sandoval 		unpack_usage(EXIT_SUCCESS);
970819281eeSdp-arm 
971819281eeSdp-arm 	parse_fip(argv[0], NULL);
972819281eeSdp-arm 
973819281eeSdp-arm 	if (outdir[0] != '\0')
974819281eeSdp-arm 		if (chdir(outdir) == -1)
975819281eeSdp-arm 			log_err("chdir %s", outdir);
976819281eeSdp-arm 
977819281eeSdp-arm 	/* Unpack all specified images. */
978e0f083a0Sdp-arm 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
979fcab6bbeSdp-arm 		char file[PATH_MAX];
980b9589fe5Sdp-arm 		image_t *image = desc->image;
981b04efcceSdp-arm 
982e0f083a0Sdp-arm 		if (!unpack_all && desc->action != DO_UNPACK)
983819281eeSdp-arm 			continue;
984819281eeSdp-arm 
985819281eeSdp-arm 		/* Build filename. */
986e0f083a0Sdp-arm 		if (desc->action_arg == NULL)
987819281eeSdp-arm 			snprintf(file, sizeof(file), "%s.bin",
988e0f083a0Sdp-arm 			    desc->cmdline_name);
989819281eeSdp-arm 		else
990819281eeSdp-arm 			snprintf(file, sizeof(file), "%s",
991e0f083a0Sdp-arm 			    desc->action_arg);
992819281eeSdp-arm 
993b04efcceSdp-arm 		if (image == NULL) {
994b04efcceSdp-arm 			if (!unpack_all)
995fcab6bbeSdp-arm 				log_warnx("%s does not exist in %s",
996819281eeSdp-arm 				    file, argv[0]);
997819281eeSdp-arm 			continue;
998819281eeSdp-arm 		}
999819281eeSdp-arm 
1000819281eeSdp-arm 		if (access(file, F_OK) != 0 || fflag) {
1001819281eeSdp-arm 			if (verbose)
1002819281eeSdp-arm 				log_dbgx("Unpacking %s", file);
1003b04efcceSdp-arm 			write_image_to_file(image, file);
1004819281eeSdp-arm 		} else {
1005819281eeSdp-arm 			log_warnx("File %s already exists, use --force to overwrite it",
1006819281eeSdp-arm 			    file);
1007819281eeSdp-arm 		}
1008819281eeSdp-arm 	}
1009819281eeSdp-arm 
1010819281eeSdp-arm 	return 0;
1011819281eeSdp-arm }
1012819281eeSdp-arm 
10134e500525SLeonardo Sandoval static void unpack_usage(int exit_status)
1014819281eeSdp-arm {
1015819281eeSdp-arm 	toc_entry_t *toc_entry = toc_entries;
1016819281eeSdp-arm 
1017ee079320SMasahiro Yamada 	printf("fiptool unpack [opts] FIP_FILENAME\n");
1018ee079320SMasahiro Yamada 	printf("\n");
1019ee079320SMasahiro Yamada 	printf("Options:\n");
1020802b42a0SMasahiro Yamada 	printf("  --blob uuid=...,file=...\tUnpack an image with the given UUID to file.\n");
1021802b42a0SMasahiro Yamada 	printf("  --force\t\t\tIf the output file already exists, use --force to overwrite it.\n");
1022fcab6bbeSdp-arm 	printf("  --out path\t\t\tSet the output directory path.\n");
102395d2b268SMasahiro Yamada 	printf("\n");
1024819281eeSdp-arm 	printf("Specific images are unpacked with the following options:\n");
1025819281eeSdp-arm 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
1026819281eeSdp-arm 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
1027819281eeSdp-arm 		    toc_entry->name);
10283527d6d2SPankaj Gupta #ifdef PLAT_DEF_FIP_UUID
10293527d6d2SPankaj Gupta 	toc_entry = plat_def_toc_entries;
10303527d6d2SPankaj Gupta 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
10313527d6d2SPankaj Gupta 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
10323527d6d2SPankaj Gupta 		    toc_entry->name);
10333527d6d2SPankaj Gupta #endif
103495d2b268SMasahiro Yamada 	printf("\n");
1035819281eeSdp-arm 	printf("If no options are provided, all images will be unpacked.\n");
10364e500525SLeonardo Sandoval 	exit(exit_status);
1037819281eeSdp-arm }
1038819281eeSdp-arm 
1039819281eeSdp-arm static int remove_cmd(int argc, char *argv[])
1040819281eeSdp-arm {
1041e0f083a0Sdp-arm 	struct option *opts = NULL;
1042e0f083a0Sdp-arm 	size_t nr_opts = 0;
1043fcab6bbeSdp-arm 	char outfile[PATH_MAX] = { 0 };
1044819281eeSdp-arm 	fip_toc_header_t toc_header;
1045e0f083a0Sdp-arm 	image_desc_t *desc;
10461c75d5dfSMasahiro Yamada 	unsigned long align = 1;
1047819281eeSdp-arm 	int fflag = 0;
1048819281eeSdp-arm 
1049819281eeSdp-arm 	if (argc < 2)
10504e500525SLeonardo Sandoval 		remove_usage(EXIT_FAILURE);
1051819281eeSdp-arm 
1052e0f083a0Sdp-arm 	opts = fill_common_opts(opts, &nr_opts, no_argument);
10531c75d5dfSMasahiro Yamada 	opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
1054fcab6bbeSdp-arm 	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
1055e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
1056e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
1057e0f083a0Sdp-arm 	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
1058819281eeSdp-arm 
1059819281eeSdp-arm 	while (1) {
106020f87e78Sdp-arm 		int c, opt_index = 0;
1061819281eeSdp-arm 
1062fcab6bbeSdp-arm 		c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
1063819281eeSdp-arm 		if (c == -1)
1064819281eeSdp-arm 			break;
1065819281eeSdp-arm 
1066819281eeSdp-arm 		switch (c) {
1067e0f083a0Sdp-arm 		case OPT_TOC_ENTRY: {
1068e0f083a0Sdp-arm 			image_desc_t *desc;
1069e0f083a0Sdp-arm 
1070e0f083a0Sdp-arm 			desc = lookup_image_desc_from_opt(opts[opt_index].name);
1071d02fcebeSdp-arm 			set_image_desc_action(desc, DO_REMOVE, NULL);
1072819281eeSdp-arm 			break;
1073e0f083a0Sdp-arm 		}
10741c75d5dfSMasahiro Yamada 		case OPT_ALIGN:
10751c75d5dfSMasahiro Yamada 			align = get_image_align(optarg);
10761c75d5dfSMasahiro Yamada 			break;
1077fcab6bbeSdp-arm 		case 'b': {
1078fcab6bbeSdp-arm 			char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
107903364865SRoberto Vargas 			uuid_t uuid = uuid_null;
1080fcab6bbeSdp-arm 			image_desc_t *desc;
1081fcab6bbeSdp-arm 
1082fcab6bbeSdp-arm 			parse_blob_opt(optarg, &uuid,
1083fcab6bbeSdp-arm 			    filename, sizeof(filename));
1084fcab6bbeSdp-arm 
1085fcab6bbeSdp-arm 			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0)
10864e500525SLeonardo Sandoval 				remove_usage(EXIT_FAILURE);
1087fcab6bbeSdp-arm 
1088fcab6bbeSdp-arm 			desc = lookup_image_desc_from_uuid(&uuid);
1089d02fcebeSdp-arm 			if (desc == NULL) {
1090fcab6bbeSdp-arm 				uuid_to_str(name, sizeof(name), &uuid);
1091fcab6bbeSdp-arm 				desc = new_image_desc(&uuid, name, "blob");
1092fcab6bbeSdp-arm 				add_image_desc(desc);
1093fcab6bbeSdp-arm 			}
1094d02fcebeSdp-arm 			set_image_desc_action(desc, DO_REMOVE, NULL);
1095fcab6bbeSdp-arm 			break;
1096fcab6bbeSdp-arm 		}
1097819281eeSdp-arm 		case 'f':
1098819281eeSdp-arm 			fflag = 1;
1099819281eeSdp-arm 			break;
1100819281eeSdp-arm 		case 'o':
1101819281eeSdp-arm 			snprintf(outfile, sizeof(outfile), "%s", optarg);
1102819281eeSdp-arm 			break;
1103819281eeSdp-arm 		default:
11044e500525SLeonardo Sandoval 			remove_usage(EXIT_FAILURE);
1105819281eeSdp-arm 		}
1106819281eeSdp-arm 	}
1107819281eeSdp-arm 	argc -= optind;
1108819281eeSdp-arm 	argv += optind;
1109e0f083a0Sdp-arm 	free(opts);
1110819281eeSdp-arm 
1111819281eeSdp-arm 	if (argc == 0)
11124e500525SLeonardo Sandoval 		remove_usage(EXIT_SUCCESS);
1113819281eeSdp-arm 
1114819281eeSdp-arm 	if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag)
1115819281eeSdp-arm 		log_errx("File %s already exists, use --force to overwrite it",
1116819281eeSdp-arm 		    outfile);
1117819281eeSdp-arm 
1118819281eeSdp-arm 	if (outfile[0] == '\0')
1119819281eeSdp-arm 		snprintf(outfile, sizeof(outfile), "%s", argv[0]);
1120819281eeSdp-arm 
1121819281eeSdp-arm 	parse_fip(argv[0], &toc_header);
1122819281eeSdp-arm 
1123e0f083a0Sdp-arm 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
1124e0f083a0Sdp-arm 		if (desc->action != DO_REMOVE)
1125819281eeSdp-arm 			continue;
1126fcab6bbeSdp-arm 
1127b9589fe5Sdp-arm 		if (desc->image != NULL) {
1128819281eeSdp-arm 			if (verbose)
1129fcab6bbeSdp-arm 				log_dbgx("Removing %s",
1130e0f083a0Sdp-arm 				    desc->cmdline_name);
1131b9589fe5Sdp-arm 			free(desc->image);
1132b9589fe5Sdp-arm 			desc->image = NULL;
1133819281eeSdp-arm 		} else {
1134fcab6bbeSdp-arm 			log_warnx("%s does not exist in %s",
1135e0f083a0Sdp-arm 			    desc->cmdline_name, argv[0]);
1136819281eeSdp-arm 		}
1137819281eeSdp-arm 	}
1138819281eeSdp-arm 
11391c75d5dfSMasahiro Yamada 	pack_images(outfile, toc_header.flags, align);
1140819281eeSdp-arm 	return 0;
1141819281eeSdp-arm }
1142819281eeSdp-arm 
11434e500525SLeonardo Sandoval static void remove_usage(int exit_status)
1144819281eeSdp-arm {
1145819281eeSdp-arm 	toc_entry_t *toc_entry = toc_entries;
1146819281eeSdp-arm 
1147ee079320SMasahiro Yamada 	printf("fiptool remove [opts] FIP_FILENAME\n");
1148ee079320SMasahiro Yamada 	printf("\n");
1149ee079320SMasahiro Yamada 	printf("Options:\n");
11501c75d5dfSMasahiro Yamada 	printf("  --align <value>\tEach image is aligned to <value> (default: 1).\n");
1151fcab6bbeSdp-arm 	printf("  --blob uuid=...\tRemove an image with the given UUID.\n");
1152802b42a0SMasahiro Yamada 	printf("  --force\t\tIf the output FIP file already exists, use --force to overwrite it.\n");
1153819281eeSdp-arm 	printf("  --out FIP_FILENAME\tSet an alternative output FIP file.\n");
115495d2b268SMasahiro Yamada 	printf("\n");
1155819281eeSdp-arm 	printf("Specific images are removed with the following options:\n");
1156819281eeSdp-arm 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
1157819281eeSdp-arm 		printf("  --%-16s\t%s\n", toc_entry->cmdline_name,
1158819281eeSdp-arm 		    toc_entry->name);
11593527d6d2SPankaj Gupta #ifdef PLAT_DEF_FIP_UUID
11603527d6d2SPankaj Gupta 	toc_entry = plat_def_toc_entries;
11613527d6d2SPankaj Gupta 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
11623527d6d2SPankaj Gupta 		printf("  --%-16s\t%s\n", toc_entry->cmdline_name,
11633527d6d2SPankaj Gupta 		    toc_entry->name);
11643527d6d2SPankaj Gupta #endif
11654e500525SLeonardo Sandoval 	exit(exit_status);
1166819281eeSdp-arm }
1167819281eeSdp-arm 
1168819281eeSdp-arm static int version_cmd(int argc, char *argv[])
1169819281eeSdp-arm {
1170819281eeSdp-arm #ifdef VERSION
1171819281eeSdp-arm 	puts(VERSION);
1172819281eeSdp-arm #else
1173819281eeSdp-arm 	/* If built from fiptool directory, VERSION is not set. */
1174819281eeSdp-arm 	puts("Unknown version");
1175819281eeSdp-arm #endif
1176819281eeSdp-arm 	return 0;
1177819281eeSdp-arm }
1178819281eeSdp-arm 
11794e500525SLeonardo Sandoval static void version_usage(int exit_status)
1180819281eeSdp-arm {
1181819281eeSdp-arm 	printf("fiptool version\n");
11824e500525SLeonardo Sandoval 	exit(exit_status);
1183819281eeSdp-arm }
1184819281eeSdp-arm 
1185819281eeSdp-arm static int help_cmd(int argc, char *argv[])
1186819281eeSdp-arm {
1187819281eeSdp-arm 	int i;
1188819281eeSdp-arm 
1189819281eeSdp-arm 	if (argc < 2)
1190819281eeSdp-arm 		usage();
1191819281eeSdp-arm 	argc--, argv++;
1192819281eeSdp-arm 
1193819281eeSdp-arm 	for (i = 0; i < NELEM(cmds); i++) {
1194819281eeSdp-arm 		if (strcmp(cmds[i].name, argv[0]) == 0 &&
119585ee2778Sdp-arm 		    cmds[i].usage != NULL)
11964e500525SLeonardo Sandoval 			cmds[i].usage(EXIT_SUCCESS);
1197819281eeSdp-arm 	}
1198819281eeSdp-arm 	if (i == NELEM(cmds))
1199819281eeSdp-arm 		printf("No help for subcommand '%s'\n", argv[0]);
1200819281eeSdp-arm 	return 0;
1201819281eeSdp-arm }
1202819281eeSdp-arm 
1203819281eeSdp-arm static void usage(void)
1204819281eeSdp-arm {
12054f96a498SMasahiro Yamada 	printf("usage: fiptool [--verbose] <command> [<args>]\n");
1206819281eeSdp-arm 	printf("Global options supported:\n");
1207819281eeSdp-arm 	printf("  --verbose\tEnable verbose output for all commands.\n");
120895d2b268SMasahiro Yamada 	printf("\n");
1209819281eeSdp-arm 	printf("Commands supported:\n");
1210819281eeSdp-arm 	printf("  info\t\tList images contained in FIP.\n");
1211819281eeSdp-arm 	printf("  create\tCreate a new FIP with the given images.\n");
1212819281eeSdp-arm 	printf("  update\tUpdate an existing FIP with the given images.\n");
1213819281eeSdp-arm 	printf("  unpack\tUnpack images from FIP.\n");
1214819281eeSdp-arm 	printf("  remove\tRemove images from FIP.\n");
1215819281eeSdp-arm 	printf("  version\tShow fiptool version.\n");
1216819281eeSdp-arm 	printf("  help\t\tShow help for given command.\n");
12174e500525SLeonardo Sandoval 	exit(EXIT_SUCCESS);
1218819281eeSdp-arm }
1219819281eeSdp-arm 
1220819281eeSdp-arm int main(int argc, char *argv[])
1221819281eeSdp-arm {
1222819281eeSdp-arm 	int i, ret = 0;
1223819281eeSdp-arm 
1224cc672bb2Sdp-arm 	while (1) {
1225cc672bb2Sdp-arm 		int c, opt_index = 0;
1226cc672bb2Sdp-arm 		static struct option opts[] = {
1227cc672bb2Sdp-arm 			{ "verbose", no_argument, NULL, 'v' },
1228cc672bb2Sdp-arm 			{ NULL, no_argument, NULL, 0 }
1229cc672bb2Sdp-arm 		};
1230819281eeSdp-arm 
1231cc672bb2Sdp-arm 		/*
1232cc672bb2Sdp-arm 		 * Set POSIX mode so getopt stops at the first non-option
1233cc672bb2Sdp-arm 		 * which is the subcommand.
1234cc672bb2Sdp-arm 		 */
1235cc672bb2Sdp-arm 		c = getopt_long(argc, argv, "+v", opts, &opt_index);
1236cc672bb2Sdp-arm 		if (c == -1)
1237cc672bb2Sdp-arm 			break;
1238cc672bb2Sdp-arm 
1239cc672bb2Sdp-arm 		switch (c) {
1240cc672bb2Sdp-arm 		case 'v':
1241819281eeSdp-arm 			verbose = 1;
1242cc672bb2Sdp-arm 			break;
1243cc672bb2Sdp-arm 		default:
1244c9cb4089SMasahiro Yamada 			usage();
1245819281eeSdp-arm 		}
1246cc672bb2Sdp-arm 	}
1247cc672bb2Sdp-arm 	argc -= optind;
1248cc672bb2Sdp-arm 	argv += optind;
1249cc672bb2Sdp-arm 	/* Reset optind for subsequent getopt processing. */
1250cc672bb2Sdp-arm 	optind = 0;
1251cc672bb2Sdp-arm 
1252cc672bb2Sdp-arm 	if (argc == 0)
1253cc672bb2Sdp-arm 		usage();
1254819281eeSdp-arm 
1255e0f083a0Sdp-arm 	fill_image_descs();
1256819281eeSdp-arm 	for (i = 0; i < NELEM(cmds); i++) {
1257819281eeSdp-arm 		if (strcmp(cmds[i].name, argv[0]) == 0) {
1258819281eeSdp-arm 			ret = cmds[i].handler(argc, argv);
1259819281eeSdp-arm 			break;
1260819281eeSdp-arm 		}
1261819281eeSdp-arm 	}
1262819281eeSdp-arm 	if (i == NELEM(cmds))
1263819281eeSdp-arm 		usage();
1264e0f083a0Sdp-arm 	free_image_descs();
1265819281eeSdp-arm 	return ret;
1266819281eeSdp-arm }
1267