xref: /aosp_15_r20/external/arm-trusted-firmware/tools/fiptool/fiptool.c (revision 54fd6939e177f8ff529b10183254802c76df6d08)
1*54fd6939SJiyong Park /*
2*54fd6939SJiyong Park  * Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
3*54fd6939SJiyong Park  *
4*54fd6939SJiyong Park  * SPDX-License-Identifier: BSD-3-Clause
5*54fd6939SJiyong Park  */
6*54fd6939SJiyong Park 
7*54fd6939SJiyong Park #include <sys/types.h>
8*54fd6939SJiyong Park #include <sys/stat.h>
9*54fd6939SJiyong Park 
10*54fd6939SJiyong Park #include <assert.h>
11*54fd6939SJiyong Park #include <errno.h>
12*54fd6939SJiyong Park #include <limits.h>
13*54fd6939SJiyong Park #include <stdarg.h>
14*54fd6939SJiyong Park #include <stdint.h>
15*54fd6939SJiyong Park #include <stdio.h>
16*54fd6939SJiyong Park #include <stdlib.h>
17*54fd6939SJiyong Park #include <string.h>
18*54fd6939SJiyong Park 
19*54fd6939SJiyong Park #include "fiptool.h"
20*54fd6939SJiyong Park #include "tbbr_config.h"
21*54fd6939SJiyong Park 
22*54fd6939SJiyong Park #define OPT_TOC_ENTRY 0
23*54fd6939SJiyong Park #define OPT_PLAT_TOC_FLAGS 1
24*54fd6939SJiyong Park #define OPT_ALIGN 2
25*54fd6939SJiyong Park 
26*54fd6939SJiyong Park static int info_cmd(int argc, char *argv[]);
27*54fd6939SJiyong Park static void info_usage(int);
28*54fd6939SJiyong Park static int create_cmd(int argc, char *argv[]);
29*54fd6939SJiyong Park static void create_usage(int);
30*54fd6939SJiyong Park static int update_cmd(int argc, char *argv[]);
31*54fd6939SJiyong Park static void update_usage(int);
32*54fd6939SJiyong Park static int unpack_cmd(int argc, char *argv[]);
33*54fd6939SJiyong Park static void unpack_usage(int);
34*54fd6939SJiyong Park static int remove_cmd(int argc, char *argv[]);
35*54fd6939SJiyong Park static void remove_usage(int);
36*54fd6939SJiyong Park static int version_cmd(int argc, char *argv[]);
37*54fd6939SJiyong Park static void version_usage(int);
38*54fd6939SJiyong Park static int help_cmd(int argc, char *argv[]);
39*54fd6939SJiyong Park static void usage(void);
40*54fd6939SJiyong Park 
41*54fd6939SJiyong Park /* Available subcommands. */
42*54fd6939SJiyong Park static cmd_t cmds[] = {
43*54fd6939SJiyong Park 	{ .name = "info",    .handler = info_cmd,    .usage = info_usage    },
44*54fd6939SJiyong Park 	{ .name = "create",  .handler = create_cmd,  .usage = create_usage  },
45*54fd6939SJiyong Park 	{ .name = "update",  .handler = update_cmd,  .usage = update_usage  },
46*54fd6939SJiyong Park 	{ .name = "unpack",  .handler = unpack_cmd,  .usage = unpack_usage  },
47*54fd6939SJiyong Park 	{ .name = "remove",  .handler = remove_cmd,  .usage = remove_usage  },
48*54fd6939SJiyong Park 	{ .name = "version", .handler = version_cmd, .usage = version_usage },
49*54fd6939SJiyong Park 	{ .name = "help",    .handler = help_cmd,    .usage = NULL          },
50*54fd6939SJiyong Park };
51*54fd6939SJiyong Park 
52*54fd6939SJiyong Park static image_desc_t *image_desc_head;
53*54fd6939SJiyong Park static size_t nr_image_descs;
54*54fd6939SJiyong Park static const uuid_t uuid_null;
55*54fd6939SJiyong Park static int verbose;
56*54fd6939SJiyong Park 
vlog(int prio,const char * msg,va_list ap)57*54fd6939SJiyong Park static void vlog(int prio, const char *msg, va_list ap)
58*54fd6939SJiyong Park {
59*54fd6939SJiyong Park 	char *prefix[] = { "DEBUG", "WARN", "ERROR" };
60*54fd6939SJiyong Park 
61*54fd6939SJiyong Park 	fprintf(stderr, "%s: ", prefix[prio]);
62*54fd6939SJiyong Park 	vfprintf(stderr, msg, ap);
63*54fd6939SJiyong Park 	fputc('\n', stderr);
64*54fd6939SJiyong Park }
65*54fd6939SJiyong Park 
log_dbgx(const char * msg,...)66*54fd6939SJiyong Park static void log_dbgx(const char *msg, ...)
67*54fd6939SJiyong Park {
68*54fd6939SJiyong Park 	va_list ap;
69*54fd6939SJiyong Park 
70*54fd6939SJiyong Park 	va_start(ap, msg);
71*54fd6939SJiyong Park 	vlog(LOG_DBG, msg, ap);
72*54fd6939SJiyong Park 	va_end(ap);
73*54fd6939SJiyong Park }
74*54fd6939SJiyong Park 
log_warnx(const char * msg,...)75*54fd6939SJiyong Park static void log_warnx(const char *msg, ...)
76*54fd6939SJiyong Park {
77*54fd6939SJiyong Park 	va_list ap;
78*54fd6939SJiyong Park 
79*54fd6939SJiyong Park 	va_start(ap, msg);
80*54fd6939SJiyong Park 	vlog(LOG_WARN, msg, ap);
81*54fd6939SJiyong Park 	va_end(ap);
82*54fd6939SJiyong Park }
83*54fd6939SJiyong Park 
log_err(const char * msg,...)84*54fd6939SJiyong Park static void log_err(const char *msg, ...)
85*54fd6939SJiyong Park {
86*54fd6939SJiyong Park 	char buf[512];
87*54fd6939SJiyong Park 	va_list ap;
88*54fd6939SJiyong Park 
89*54fd6939SJiyong Park 	va_start(ap, msg);
90*54fd6939SJiyong Park 	snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno));
91*54fd6939SJiyong Park 	vlog(LOG_ERR, buf, ap);
92*54fd6939SJiyong Park 	va_end(ap);
93*54fd6939SJiyong Park 	exit(1);
94*54fd6939SJiyong Park }
95*54fd6939SJiyong Park 
log_errx(const char * msg,...)96*54fd6939SJiyong Park static void log_errx(const char *msg, ...)
97*54fd6939SJiyong Park {
98*54fd6939SJiyong Park 	va_list ap;
99*54fd6939SJiyong Park 
100*54fd6939SJiyong Park 	va_start(ap, msg);
101*54fd6939SJiyong Park 	vlog(LOG_ERR, msg, ap);
102*54fd6939SJiyong Park 	va_end(ap);
103*54fd6939SJiyong Park 	exit(1);
104*54fd6939SJiyong Park }
105*54fd6939SJiyong Park 
xstrdup(const char * s,const char * msg)106*54fd6939SJiyong Park static char *xstrdup(const char *s, const char *msg)
107*54fd6939SJiyong Park {
108*54fd6939SJiyong Park 	char *d;
109*54fd6939SJiyong Park 
110*54fd6939SJiyong Park 	d = strdup(s);
111*54fd6939SJiyong Park 	if (d == NULL)
112*54fd6939SJiyong Park 		log_errx("strdup: %s", msg);
113*54fd6939SJiyong Park 	return d;
114*54fd6939SJiyong Park }
115*54fd6939SJiyong Park 
xmalloc(size_t size,const char * msg)116*54fd6939SJiyong Park static void *xmalloc(size_t size, const char *msg)
117*54fd6939SJiyong Park {
118*54fd6939SJiyong Park 	void *d;
119*54fd6939SJiyong Park 
120*54fd6939SJiyong Park 	d = malloc(size);
121*54fd6939SJiyong Park 	if (d == NULL)
122*54fd6939SJiyong Park 		log_errx("malloc: %s", msg);
123*54fd6939SJiyong Park 	return d;
124*54fd6939SJiyong Park }
125*54fd6939SJiyong Park 
xzalloc(size_t size,const char * msg)126*54fd6939SJiyong Park static void *xzalloc(size_t size, const char *msg)
127*54fd6939SJiyong Park {
128*54fd6939SJiyong Park 	return memset(xmalloc(size, msg), 0, size);
129*54fd6939SJiyong Park }
130*54fd6939SJiyong Park 
xfwrite(void * buf,size_t size,FILE * fp,const char * filename)131*54fd6939SJiyong Park static void xfwrite(void *buf, size_t size, FILE *fp, const char *filename)
132*54fd6939SJiyong Park {
133*54fd6939SJiyong Park 	if (fwrite(buf, 1, size, fp) != size)
134*54fd6939SJiyong Park 		log_errx("Failed to write %s", filename);
135*54fd6939SJiyong Park }
136*54fd6939SJiyong Park 
new_image_desc(const uuid_t * uuid,const char * name,const char * cmdline_name)137*54fd6939SJiyong Park static image_desc_t *new_image_desc(const uuid_t *uuid,
138*54fd6939SJiyong Park     const char *name, const char *cmdline_name)
139*54fd6939SJiyong Park {
140*54fd6939SJiyong Park 	image_desc_t *desc;
141*54fd6939SJiyong Park 
142*54fd6939SJiyong Park 	desc = xzalloc(sizeof(*desc),
143*54fd6939SJiyong Park 	    "failed to allocate memory for image descriptor");
144*54fd6939SJiyong Park 	memcpy(&desc->uuid, uuid, sizeof(uuid_t));
145*54fd6939SJiyong Park 	desc->name = xstrdup(name,
146*54fd6939SJiyong Park 	    "failed to allocate memory for image name");
147*54fd6939SJiyong Park 	desc->cmdline_name = xstrdup(cmdline_name,
148*54fd6939SJiyong Park 	    "failed to allocate memory for image command line name");
149*54fd6939SJiyong Park 	desc->action = DO_UNSPEC;
150*54fd6939SJiyong Park 	return desc;
151*54fd6939SJiyong Park }
152*54fd6939SJiyong Park 
set_image_desc_action(image_desc_t * desc,int action,const char * arg)153*54fd6939SJiyong Park static void set_image_desc_action(image_desc_t *desc, int action,
154*54fd6939SJiyong Park     const char *arg)
155*54fd6939SJiyong Park {
156*54fd6939SJiyong Park 	assert(desc != NULL);
157*54fd6939SJiyong Park 
158*54fd6939SJiyong Park 	if (desc->action_arg != (char *)DO_UNSPEC)
159*54fd6939SJiyong Park 		free(desc->action_arg);
160*54fd6939SJiyong Park 	desc->action = action;
161*54fd6939SJiyong Park 	desc->action_arg = NULL;
162*54fd6939SJiyong Park 	if (arg != NULL)
163*54fd6939SJiyong Park 		desc->action_arg = xstrdup(arg,
164*54fd6939SJiyong Park 		    "failed to allocate memory for argument");
165*54fd6939SJiyong Park }
166*54fd6939SJiyong Park 
free_image_desc(image_desc_t * desc)167*54fd6939SJiyong Park static void free_image_desc(image_desc_t *desc)
168*54fd6939SJiyong Park {
169*54fd6939SJiyong Park 	free(desc->name);
170*54fd6939SJiyong Park 	free(desc->cmdline_name);
171*54fd6939SJiyong Park 	free(desc->action_arg);
172*54fd6939SJiyong Park 	if (desc->image) {
173*54fd6939SJiyong Park 		free(desc->image->buffer);
174*54fd6939SJiyong Park 		free(desc->image);
175*54fd6939SJiyong Park 	}
176*54fd6939SJiyong Park 	free(desc);
177*54fd6939SJiyong Park }
178*54fd6939SJiyong Park 
add_image_desc(image_desc_t * desc)179*54fd6939SJiyong Park static void add_image_desc(image_desc_t *desc)
180*54fd6939SJiyong Park {
181*54fd6939SJiyong Park 	image_desc_t **p = &image_desc_head;
182*54fd6939SJiyong Park 
183*54fd6939SJiyong Park 	while (*p)
184*54fd6939SJiyong Park 		p = &(*p)->next;
185*54fd6939SJiyong Park 
186*54fd6939SJiyong Park 	assert(*p == NULL);
187*54fd6939SJiyong Park 	*p = desc;
188*54fd6939SJiyong Park 	nr_image_descs++;
189*54fd6939SJiyong Park }
190*54fd6939SJiyong Park 
free_image_descs(void)191*54fd6939SJiyong Park static void free_image_descs(void)
192*54fd6939SJiyong Park {
193*54fd6939SJiyong Park 	image_desc_t *desc = image_desc_head, *tmp;
194*54fd6939SJiyong Park 
195*54fd6939SJiyong Park 	while (desc != NULL) {
196*54fd6939SJiyong Park 		tmp = desc->next;
197*54fd6939SJiyong Park 		free_image_desc(desc);
198*54fd6939SJiyong Park 		desc = tmp;
199*54fd6939SJiyong Park 		nr_image_descs--;
200*54fd6939SJiyong Park 	}
201*54fd6939SJiyong Park 	assert(nr_image_descs == 0);
202*54fd6939SJiyong Park }
203*54fd6939SJiyong Park 
fill_image_descs(void)204*54fd6939SJiyong Park static void fill_image_descs(void)
205*54fd6939SJiyong Park {
206*54fd6939SJiyong Park 	toc_entry_t *toc_entry;
207*54fd6939SJiyong Park 
208*54fd6939SJiyong Park 	for (toc_entry = toc_entries;
209*54fd6939SJiyong Park 	     toc_entry->cmdline_name != NULL;
210*54fd6939SJiyong Park 	     toc_entry++) {
211*54fd6939SJiyong Park 		image_desc_t *desc;
212*54fd6939SJiyong Park 
213*54fd6939SJiyong Park 		desc = new_image_desc(&toc_entry->uuid,
214*54fd6939SJiyong Park 		    toc_entry->name,
215*54fd6939SJiyong Park 		    toc_entry->cmdline_name);
216*54fd6939SJiyong Park 		add_image_desc(desc);
217*54fd6939SJiyong Park 	}
218*54fd6939SJiyong Park #ifdef PLAT_DEF_FIP_UUID
219*54fd6939SJiyong Park 	for (toc_entry = plat_def_toc_entries;
220*54fd6939SJiyong Park 	     toc_entry->cmdline_name != NULL;
221*54fd6939SJiyong Park 	     toc_entry++) {
222*54fd6939SJiyong Park 		image_desc_t *desc;
223*54fd6939SJiyong Park 
224*54fd6939SJiyong Park 		desc = new_image_desc(&toc_entry->uuid,
225*54fd6939SJiyong Park 		    toc_entry->name,
226*54fd6939SJiyong Park 		    toc_entry->cmdline_name);
227*54fd6939SJiyong Park 		add_image_desc(desc);
228*54fd6939SJiyong Park 	}
229*54fd6939SJiyong Park #endif
230*54fd6939SJiyong Park }
231*54fd6939SJiyong Park 
lookup_image_desc_from_uuid(const uuid_t * uuid)232*54fd6939SJiyong Park static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid)
233*54fd6939SJiyong Park {
234*54fd6939SJiyong Park 	image_desc_t *desc;
235*54fd6939SJiyong Park 
236*54fd6939SJiyong Park 	for (desc = image_desc_head; desc != NULL; desc = desc->next)
237*54fd6939SJiyong Park 		if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0)
238*54fd6939SJiyong Park 			return desc;
239*54fd6939SJiyong Park 	return NULL;
240*54fd6939SJiyong Park }
241*54fd6939SJiyong Park 
lookup_image_desc_from_opt(const char * opt)242*54fd6939SJiyong Park static image_desc_t *lookup_image_desc_from_opt(const char *opt)
243*54fd6939SJiyong Park {
244*54fd6939SJiyong Park 	image_desc_t *desc;
245*54fd6939SJiyong Park 
246*54fd6939SJiyong Park 	for (desc = image_desc_head; desc != NULL; desc = desc->next)
247*54fd6939SJiyong Park 		if (strcmp(desc->cmdline_name, opt) == 0)
248*54fd6939SJiyong Park 			return desc;
249*54fd6939SJiyong Park 	return NULL;
250*54fd6939SJiyong Park }
251*54fd6939SJiyong Park 
uuid_to_str(char * s,size_t len,const uuid_t * u)252*54fd6939SJiyong Park static void uuid_to_str(char *s, size_t len, const uuid_t *u)
253*54fd6939SJiyong Park {
254*54fd6939SJiyong Park 	assert(len >= (_UUID_STR_LEN + 1));
255*54fd6939SJiyong Park 
256*54fd6939SJiyong Park 	snprintf(s, len,
257*54fd6939SJiyong Park 	    "%02X%02X%02X%02X-%02X%02X-%02X%02X-%04X-%04X%04X%04X",
258*54fd6939SJiyong Park 	    u->time_low[0], u->time_low[1], u->time_low[2], u->time_low[3],
259*54fd6939SJiyong Park 	    u->time_mid[0], u->time_mid[1],
260*54fd6939SJiyong Park 	    u->time_hi_and_version[0], u->time_hi_and_version[1],
261*54fd6939SJiyong Park 	    (u->clock_seq_hi_and_reserved << 8) | u->clock_seq_low,
262*54fd6939SJiyong Park 	    (u->node[0] << 8) | u->node[1],
263*54fd6939SJiyong Park 	    (u->node[2] << 8) | u->node[3],
264*54fd6939SJiyong Park 	    (u->node[4] << 8) | u->node[5]);
265*54fd6939SJiyong Park }
266*54fd6939SJiyong Park 
uuid_from_str(uuid_t * u,const char * s)267*54fd6939SJiyong Park static void uuid_from_str(uuid_t *u, const char *s)
268*54fd6939SJiyong Park {
269*54fd6939SJiyong Park 	int n;
270*54fd6939SJiyong Park 
271*54fd6939SJiyong Park 	if (s == NULL)
272*54fd6939SJiyong Park 		log_errx("UUID cannot be NULL");
273*54fd6939SJiyong Park 	if (strlen(s) != _UUID_STR_LEN)
274*54fd6939SJiyong Park 		log_errx("Invalid UUID: %s", s);
275*54fd6939SJiyong Park 
276*54fd6939SJiyong Park 	n = sscanf(s,
277*54fd6939SJiyong Park 	    "%2hhx%2hhx%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
278*54fd6939SJiyong Park 	    &u->time_low[0], &u->time_low[1], &u->time_low[2], &u->time_low[3],
279*54fd6939SJiyong Park 	    &u->time_mid[0], &u->time_mid[1],
280*54fd6939SJiyong Park 	    &u->time_hi_and_version[0], &u->time_hi_and_version[1],
281*54fd6939SJiyong Park 	    &u->clock_seq_hi_and_reserved, &u->clock_seq_low,
282*54fd6939SJiyong Park 	    &u->node[0], &u->node[1],
283*54fd6939SJiyong Park 	    &u->node[2], &u->node[3],
284*54fd6939SJiyong Park 	    &u->node[4], &u->node[5]);
285*54fd6939SJiyong Park 	/*
286*54fd6939SJiyong Park 	 * Given the format specifier above, we expect 16 items to be scanned
287*54fd6939SJiyong Park 	 * for a properly formatted UUID.
288*54fd6939SJiyong Park 	 */
289*54fd6939SJiyong Park 	if (n != 16)
290*54fd6939SJiyong Park 		log_errx("Invalid UUID: %s", s);
291*54fd6939SJiyong Park }
292*54fd6939SJiyong Park 
parse_fip(const char * filename,fip_toc_header_t * toc_header_out)293*54fd6939SJiyong Park static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
294*54fd6939SJiyong Park {
295*54fd6939SJiyong Park 	struct BLD_PLAT_STAT st;
296*54fd6939SJiyong Park 	FILE *fp;
297*54fd6939SJiyong Park 	char *buf, *bufend;
298*54fd6939SJiyong Park 	fip_toc_header_t *toc_header;
299*54fd6939SJiyong Park 	fip_toc_entry_t *toc_entry;
300*54fd6939SJiyong Park 	int terminated = 0;
301*54fd6939SJiyong Park 
302*54fd6939SJiyong Park 	fp = fopen(filename, "rb");
303*54fd6939SJiyong Park 	if (fp == NULL)
304*54fd6939SJiyong Park 		log_err("fopen %s", filename);
305*54fd6939SJiyong Park 
306*54fd6939SJiyong Park 	if (fstat(fileno(fp), &st) == -1)
307*54fd6939SJiyong Park 		log_err("fstat %s", filename);
308*54fd6939SJiyong Park 
309*54fd6939SJiyong Park 	buf = xmalloc(st.st_size, "failed to load file into memory");
310*54fd6939SJiyong Park 	if (fread(buf, 1, st.st_size, fp) != st.st_size)
311*54fd6939SJiyong Park 		log_errx("Failed to read %s", filename);
312*54fd6939SJiyong Park 	bufend = buf + st.st_size;
313*54fd6939SJiyong Park 	fclose(fp);
314*54fd6939SJiyong Park 
315*54fd6939SJiyong Park 	if (st.st_size < sizeof(fip_toc_header_t))
316*54fd6939SJiyong Park 		log_errx("FIP %s is truncated", filename);
317*54fd6939SJiyong Park 
318*54fd6939SJiyong Park 	toc_header = (fip_toc_header_t *)buf;
319*54fd6939SJiyong Park 	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
320*54fd6939SJiyong Park 
321*54fd6939SJiyong Park 	if (toc_header->name != TOC_HEADER_NAME)
322*54fd6939SJiyong Park 		log_errx("%s is not a FIP file", filename);
323*54fd6939SJiyong Park 
324*54fd6939SJiyong Park 	/* Return the ToC header if the caller wants it. */
325*54fd6939SJiyong Park 	if (toc_header_out != NULL)
326*54fd6939SJiyong Park 		*toc_header_out = *toc_header;
327*54fd6939SJiyong Park 
328*54fd6939SJiyong Park 	/* Walk through each ToC entry in the file. */
329*54fd6939SJiyong Park 	while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) {
330*54fd6939SJiyong Park 		image_t *image;
331*54fd6939SJiyong Park 		image_desc_t *desc;
332*54fd6939SJiyong Park 
333*54fd6939SJiyong Park 		/* Found the ToC terminator, we are done. */
334*54fd6939SJiyong Park 		if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) {
335*54fd6939SJiyong Park 			terminated = 1;
336*54fd6939SJiyong Park 			break;
337*54fd6939SJiyong Park 		}
338*54fd6939SJiyong Park 
339*54fd6939SJiyong Park 		/*
340*54fd6939SJiyong Park 		 * Build a new image out of the ToC entry and add it to the
341*54fd6939SJiyong Park 		 * table of images.
342*54fd6939SJiyong Park 		 */
343*54fd6939SJiyong Park 		image = xzalloc(sizeof(*image),
344*54fd6939SJiyong Park 		    "failed to allocate memory for image");
345*54fd6939SJiyong Park 		image->toc_e = *toc_entry;
346*54fd6939SJiyong Park 		image->buffer = xmalloc(toc_entry->size,
347*54fd6939SJiyong Park 		    "failed to allocate image buffer, is FIP file corrupted?");
348*54fd6939SJiyong Park 		/* Overflow checks before memory copy. */
349*54fd6939SJiyong Park 		if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address)
350*54fd6939SJiyong Park 			log_errx("FIP %s is corrupted", filename);
351*54fd6939SJiyong Park 		if (toc_entry->size + toc_entry->offset_address > st.st_size)
352*54fd6939SJiyong Park 			log_errx("FIP %s is corrupted", filename);
353*54fd6939SJiyong Park 
354*54fd6939SJiyong Park 		memcpy(image->buffer, buf + toc_entry->offset_address,
355*54fd6939SJiyong Park 		    toc_entry->size);
356*54fd6939SJiyong Park 
357*54fd6939SJiyong Park 		/* If this is an unknown image, create a descriptor for it. */
358*54fd6939SJiyong Park 		desc = lookup_image_desc_from_uuid(&toc_entry->uuid);
359*54fd6939SJiyong Park 		if (desc == NULL) {
360*54fd6939SJiyong Park 			char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
361*54fd6939SJiyong Park 
362*54fd6939SJiyong Park 			uuid_to_str(name, sizeof(name), &toc_entry->uuid);
363*54fd6939SJiyong Park 			snprintf(filename, sizeof(filename), "%s%s",
364*54fd6939SJiyong Park 			    name, ".bin");
365*54fd6939SJiyong Park 			desc = new_image_desc(&toc_entry->uuid, name, "blob");
366*54fd6939SJiyong Park 			desc->action = DO_UNPACK;
367*54fd6939SJiyong Park 			desc->action_arg = xstrdup(filename,
368*54fd6939SJiyong Park 			    "failed to allocate memory for blob filename");
369*54fd6939SJiyong Park 			add_image_desc(desc);
370*54fd6939SJiyong Park 		}
371*54fd6939SJiyong Park 
372*54fd6939SJiyong Park 		assert(desc->image == NULL);
373*54fd6939SJiyong Park 		desc->image = image;
374*54fd6939SJiyong Park 
375*54fd6939SJiyong Park 		toc_entry++;
376*54fd6939SJiyong Park 	}
377*54fd6939SJiyong Park 
378*54fd6939SJiyong Park 	if (terminated == 0)
379*54fd6939SJiyong Park 		log_errx("FIP %s does not have a ToC terminator entry",
380*54fd6939SJiyong Park 		    filename);
381*54fd6939SJiyong Park 	free(buf);
382*54fd6939SJiyong Park 	return 0;
383*54fd6939SJiyong Park }
384*54fd6939SJiyong Park 
read_image_from_file(const uuid_t * uuid,const char * filename)385*54fd6939SJiyong Park static image_t *read_image_from_file(const uuid_t *uuid, const char *filename)
386*54fd6939SJiyong Park {
387*54fd6939SJiyong Park 	struct BLD_PLAT_STAT st;
388*54fd6939SJiyong Park 	image_t *image;
389*54fd6939SJiyong Park 	FILE *fp;
390*54fd6939SJiyong Park 
391*54fd6939SJiyong Park 	assert(uuid != NULL);
392*54fd6939SJiyong Park 	assert(filename != NULL);
393*54fd6939SJiyong Park 
394*54fd6939SJiyong Park 	fp = fopen(filename, "rb");
395*54fd6939SJiyong Park 	if (fp == NULL)
396*54fd6939SJiyong Park 		log_err("fopen %s", filename);
397*54fd6939SJiyong Park 
398*54fd6939SJiyong Park 	if (fstat(fileno(fp), &st) == -1)
399*54fd6939SJiyong Park 		log_errx("fstat %s", filename);
400*54fd6939SJiyong Park 
401*54fd6939SJiyong Park 	image = xzalloc(sizeof(*image), "failed to allocate memory for image");
402*54fd6939SJiyong Park 	image->toc_e.uuid = *uuid;
403*54fd6939SJiyong Park 	image->buffer = xmalloc(st.st_size, "failed to allocate image buffer");
404*54fd6939SJiyong Park 	if (fread(image->buffer, 1, st.st_size, fp) != st.st_size)
405*54fd6939SJiyong Park 		log_errx("Failed to read %s", filename);
406*54fd6939SJiyong Park 	image->toc_e.size = st.st_size;
407*54fd6939SJiyong Park 
408*54fd6939SJiyong Park 	fclose(fp);
409*54fd6939SJiyong Park 	return image;
410*54fd6939SJiyong Park }
411*54fd6939SJiyong Park 
write_image_to_file(const image_t * image,const char * filename)412*54fd6939SJiyong Park static int write_image_to_file(const image_t *image, const char *filename)
413*54fd6939SJiyong Park {
414*54fd6939SJiyong Park 	FILE *fp;
415*54fd6939SJiyong Park 
416*54fd6939SJiyong Park 	fp = fopen(filename, "wb");
417*54fd6939SJiyong Park 	if (fp == NULL)
418*54fd6939SJiyong Park 		log_err("fopen");
419*54fd6939SJiyong Park 	xfwrite(image->buffer, image->toc_e.size, fp, filename);
420*54fd6939SJiyong Park 	fclose(fp);
421*54fd6939SJiyong Park 	return 0;
422*54fd6939SJiyong Park }
423*54fd6939SJiyong Park 
add_opt(struct option * opts,size_t * nr_opts,const char * name,int has_arg,int val)424*54fd6939SJiyong Park static struct option *add_opt(struct option *opts, size_t *nr_opts,
425*54fd6939SJiyong Park     const char *name, int has_arg, int val)
426*54fd6939SJiyong Park {
427*54fd6939SJiyong Park 	opts = realloc(opts, (*nr_opts + 1) * sizeof(*opts));
428*54fd6939SJiyong Park 	if (opts == NULL)
429*54fd6939SJiyong Park 		log_err("realloc");
430*54fd6939SJiyong Park 	opts[*nr_opts].name = name;
431*54fd6939SJiyong Park 	opts[*nr_opts].has_arg = has_arg;
432*54fd6939SJiyong Park 	opts[*nr_opts].flag = NULL;
433*54fd6939SJiyong Park 	opts[*nr_opts].val = val;
434*54fd6939SJiyong Park 	++*nr_opts;
435*54fd6939SJiyong Park 	return opts;
436*54fd6939SJiyong Park }
437*54fd6939SJiyong Park 
fill_common_opts(struct option * opts,size_t * nr_opts,int has_arg)438*54fd6939SJiyong Park static struct option *fill_common_opts(struct option *opts, size_t *nr_opts,
439*54fd6939SJiyong Park     int has_arg)
440*54fd6939SJiyong Park {
441*54fd6939SJiyong Park 	image_desc_t *desc;
442*54fd6939SJiyong Park 
443*54fd6939SJiyong Park 	for (desc = image_desc_head; desc != NULL; desc = desc->next)
444*54fd6939SJiyong Park 		opts = add_opt(opts, nr_opts, desc->cmdline_name, has_arg,
445*54fd6939SJiyong Park 		    OPT_TOC_ENTRY);
446*54fd6939SJiyong Park 	return opts;
447*54fd6939SJiyong Park }
448*54fd6939SJiyong Park 
md_print(const unsigned char * md,size_t len)449*54fd6939SJiyong Park static void md_print(const unsigned char *md, size_t len)
450*54fd6939SJiyong Park {
451*54fd6939SJiyong Park 	size_t i;
452*54fd6939SJiyong Park 
453*54fd6939SJiyong Park 	for (i = 0; i < len; i++)
454*54fd6939SJiyong Park 		printf("%02x", md[i]);
455*54fd6939SJiyong Park }
456*54fd6939SJiyong Park 
info_cmd(int argc,char * argv[])457*54fd6939SJiyong Park static int info_cmd(int argc, char *argv[])
458*54fd6939SJiyong Park {
459*54fd6939SJiyong Park 	image_desc_t *desc;
460*54fd6939SJiyong Park 	fip_toc_header_t toc_header;
461*54fd6939SJiyong Park 
462*54fd6939SJiyong Park 	if (argc != 2)
463*54fd6939SJiyong Park 		info_usage(EXIT_FAILURE);
464*54fd6939SJiyong Park 	argc--, argv++;
465*54fd6939SJiyong Park 
466*54fd6939SJiyong Park 	parse_fip(argv[0], &toc_header);
467*54fd6939SJiyong Park 
468*54fd6939SJiyong Park 	if (verbose) {
469*54fd6939SJiyong Park 		log_dbgx("toc_header[name]: 0x%llX",
470*54fd6939SJiyong Park 		    (unsigned long long)toc_header.name);
471*54fd6939SJiyong Park 		log_dbgx("toc_header[serial_number]: 0x%llX",
472*54fd6939SJiyong Park 		    (unsigned long long)toc_header.serial_number);
473*54fd6939SJiyong Park 		log_dbgx("toc_header[flags]: 0x%llX",
474*54fd6939SJiyong Park 		    (unsigned long long)toc_header.flags);
475*54fd6939SJiyong Park 	}
476*54fd6939SJiyong Park 
477*54fd6939SJiyong Park 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
478*54fd6939SJiyong Park 		image_t *image = desc->image;
479*54fd6939SJiyong Park 
480*54fd6939SJiyong Park 		if (image == NULL)
481*54fd6939SJiyong Park 			continue;
482*54fd6939SJiyong Park 		printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"--%s\"",
483*54fd6939SJiyong Park 		       desc->name,
484*54fd6939SJiyong Park 		       (unsigned long long)image->toc_e.offset_address,
485*54fd6939SJiyong Park 		       (unsigned long long)image->toc_e.size,
486*54fd6939SJiyong Park 		       desc->cmdline_name);
487*54fd6939SJiyong Park #ifndef _MSC_VER	/* We don't have SHA256 for Visual Studio. */
488*54fd6939SJiyong Park 		if (verbose) {
489*54fd6939SJiyong Park 			unsigned char md[SHA256_DIGEST_LENGTH];
490*54fd6939SJiyong Park 
491*54fd6939SJiyong Park 			SHA256(image->buffer, image->toc_e.size, md);
492*54fd6939SJiyong Park 			printf(", sha256=");
493*54fd6939SJiyong Park 			md_print(md, sizeof(md));
494*54fd6939SJiyong Park 		}
495*54fd6939SJiyong Park #endif
496*54fd6939SJiyong Park 		putchar('\n');
497*54fd6939SJiyong Park 	}
498*54fd6939SJiyong Park 
499*54fd6939SJiyong Park 	return 0;
500*54fd6939SJiyong Park }
501*54fd6939SJiyong Park 
info_usage(int exit_status)502*54fd6939SJiyong Park static void info_usage(int exit_status)
503*54fd6939SJiyong Park {
504*54fd6939SJiyong Park 	printf("fiptool info FIP_FILENAME\n");
505*54fd6939SJiyong Park 	exit(exit_status);
506*54fd6939SJiyong Park }
507*54fd6939SJiyong Park 
pack_images(const char * filename,uint64_t toc_flags,unsigned long align)508*54fd6939SJiyong Park static int pack_images(const char *filename, uint64_t toc_flags, unsigned long align)
509*54fd6939SJiyong Park {
510*54fd6939SJiyong Park 	FILE *fp;
511*54fd6939SJiyong Park 	image_desc_t *desc;
512*54fd6939SJiyong Park 	fip_toc_header_t *toc_header;
513*54fd6939SJiyong Park 	fip_toc_entry_t *toc_entry;
514*54fd6939SJiyong Park 	char *buf;
515*54fd6939SJiyong Park 	uint64_t entry_offset, buf_size, payload_size = 0, pad_size;
516*54fd6939SJiyong Park 	size_t nr_images = 0;
517*54fd6939SJiyong Park 
518*54fd6939SJiyong Park 	for (desc = image_desc_head; desc != NULL; desc = desc->next)
519*54fd6939SJiyong Park 		if (desc->image != NULL)
520*54fd6939SJiyong Park 			nr_images++;
521*54fd6939SJiyong Park 
522*54fd6939SJiyong Park 	buf_size = sizeof(fip_toc_header_t) +
523*54fd6939SJiyong Park 	    sizeof(fip_toc_entry_t) * (nr_images + 1);
524*54fd6939SJiyong Park 	buf = calloc(1, buf_size);
525*54fd6939SJiyong Park 	if (buf == NULL)
526*54fd6939SJiyong Park 		log_err("calloc");
527*54fd6939SJiyong Park 
528*54fd6939SJiyong Park 	/* Build up header and ToC entries from the image table. */
529*54fd6939SJiyong Park 	toc_header = (fip_toc_header_t *)buf;
530*54fd6939SJiyong Park 	toc_header->name = TOC_HEADER_NAME;
531*54fd6939SJiyong Park 	toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
532*54fd6939SJiyong Park 	toc_header->flags = toc_flags;
533*54fd6939SJiyong Park 
534*54fd6939SJiyong Park 	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
535*54fd6939SJiyong Park 
536*54fd6939SJiyong Park 	entry_offset = buf_size;
537*54fd6939SJiyong Park 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
538*54fd6939SJiyong Park 		image_t *image = desc->image;
539*54fd6939SJiyong Park 
540*54fd6939SJiyong Park 		if (image == NULL)
541*54fd6939SJiyong Park 			continue;
542*54fd6939SJiyong Park 		payload_size += image->toc_e.size;
543*54fd6939SJiyong Park 		entry_offset = (entry_offset + align - 1) & ~(align - 1);
544*54fd6939SJiyong Park 		image->toc_e.offset_address = entry_offset;
545*54fd6939SJiyong Park 		*toc_entry++ = image->toc_e;
546*54fd6939SJiyong Park 		entry_offset += image->toc_e.size;
547*54fd6939SJiyong Park 	}
548*54fd6939SJiyong Park 
549*54fd6939SJiyong Park 	/*
550*54fd6939SJiyong Park 	 * Append a null uuid entry to mark the end of ToC entries.
551*54fd6939SJiyong Park 	 * NOTE the offset address for the last toc_entry must match the fip
552*54fd6939SJiyong Park 	 * size.
553*54fd6939SJiyong Park 	 */
554*54fd6939SJiyong Park 	memset(toc_entry, 0, sizeof(*toc_entry));
555*54fd6939SJiyong Park 	toc_entry->offset_address = (entry_offset + align - 1) & ~(align - 1);
556*54fd6939SJiyong Park 
557*54fd6939SJiyong Park 	/* Generate the FIP file. */
558*54fd6939SJiyong Park 	fp = fopen(filename, "wb");
559*54fd6939SJiyong Park 	if (fp == NULL)
560*54fd6939SJiyong Park 		log_err("fopen %s", filename);
561*54fd6939SJiyong Park 
562*54fd6939SJiyong Park 	if (verbose)
563*54fd6939SJiyong Park 		log_dbgx("Metadata size: %zu bytes", buf_size);
564*54fd6939SJiyong Park 
565*54fd6939SJiyong Park 	xfwrite(buf, buf_size, fp, filename);
566*54fd6939SJiyong Park 
567*54fd6939SJiyong Park 	if (verbose)
568*54fd6939SJiyong Park 		log_dbgx("Payload size: %zu bytes", payload_size);
569*54fd6939SJiyong Park 
570*54fd6939SJiyong Park 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
571*54fd6939SJiyong Park 		image_t *image = desc->image;
572*54fd6939SJiyong Park 
573*54fd6939SJiyong Park 		if (image == NULL)
574*54fd6939SJiyong Park 			continue;
575*54fd6939SJiyong Park 		if (fseek(fp, image->toc_e.offset_address, SEEK_SET))
576*54fd6939SJiyong Park 			log_errx("Failed to set file position");
577*54fd6939SJiyong Park 
578*54fd6939SJiyong Park 		xfwrite(image->buffer, image->toc_e.size, fp, filename);
579*54fd6939SJiyong Park 	}
580*54fd6939SJiyong Park 
581*54fd6939SJiyong Park 	if (fseek(fp, entry_offset, SEEK_SET))
582*54fd6939SJiyong Park 		log_errx("Failed to set file position");
583*54fd6939SJiyong Park 
584*54fd6939SJiyong Park 	pad_size = toc_entry->offset_address - entry_offset;
585*54fd6939SJiyong Park 	while (pad_size--)
586*54fd6939SJiyong Park 		fputc(0x0, fp);
587*54fd6939SJiyong Park 
588*54fd6939SJiyong Park 	free(buf);
589*54fd6939SJiyong Park 	fclose(fp);
590*54fd6939SJiyong Park 	return 0;
591*54fd6939SJiyong Park }
592*54fd6939SJiyong Park 
593*54fd6939SJiyong Park /*
594*54fd6939SJiyong Park  * This function is shared between the create and update subcommands.
595*54fd6939SJiyong Park  * The difference between the two subcommands is that when the FIP file
596*54fd6939SJiyong Park  * is created, the parsing of an existing FIP is skipped.  This results
597*54fd6939SJiyong Park  * in update_fip() creating the new FIP file from scratch because the
598*54fd6939SJiyong Park  * internal image table is not populated.
599*54fd6939SJiyong Park  */
update_fip(void)600*54fd6939SJiyong Park static void update_fip(void)
601*54fd6939SJiyong Park {
602*54fd6939SJiyong Park 	image_desc_t *desc;
603*54fd6939SJiyong Park 
604*54fd6939SJiyong Park 	/* Add or replace images in the FIP file. */
605*54fd6939SJiyong Park 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
606*54fd6939SJiyong Park 		image_t *image;
607*54fd6939SJiyong Park 
608*54fd6939SJiyong Park 		if (desc->action != DO_PACK)
609*54fd6939SJiyong Park 			continue;
610*54fd6939SJiyong Park 
611*54fd6939SJiyong Park 		image = read_image_from_file(&desc->uuid,
612*54fd6939SJiyong Park 		    desc->action_arg);
613*54fd6939SJiyong Park 		if (desc->image != NULL) {
614*54fd6939SJiyong Park 			if (verbose) {
615*54fd6939SJiyong Park 				log_dbgx("Replacing %s with %s",
616*54fd6939SJiyong Park 				    desc->cmdline_name,
617*54fd6939SJiyong Park 				    desc->action_arg);
618*54fd6939SJiyong Park 			}
619*54fd6939SJiyong Park 			free(desc->image);
620*54fd6939SJiyong Park 			desc->image = image;
621*54fd6939SJiyong Park 		} else {
622*54fd6939SJiyong Park 			if (verbose)
623*54fd6939SJiyong Park 				log_dbgx("Adding image %s",
624*54fd6939SJiyong Park 				    desc->action_arg);
625*54fd6939SJiyong Park 			desc->image = image;
626*54fd6939SJiyong Park 		}
627*54fd6939SJiyong Park 	}
628*54fd6939SJiyong Park }
629*54fd6939SJiyong Park 
parse_plat_toc_flags(const char * arg,unsigned long long * toc_flags)630*54fd6939SJiyong Park static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags)
631*54fd6939SJiyong Park {
632*54fd6939SJiyong Park 	unsigned long long flags;
633*54fd6939SJiyong Park 	char *endptr;
634*54fd6939SJiyong Park 
635*54fd6939SJiyong Park 	errno = 0;
636*54fd6939SJiyong Park 	flags = strtoull(arg, &endptr, 16);
637*54fd6939SJiyong Park 	if (*endptr != '\0' || flags > UINT16_MAX || errno != 0)
638*54fd6939SJiyong Park 		log_errx("Invalid platform ToC flags: %s", arg);
639*54fd6939SJiyong Park 	/* Platform ToC flags is a 16-bit field occupying bits [32-47]. */
640*54fd6939SJiyong Park 	*toc_flags |= flags << 32;
641*54fd6939SJiyong Park }
642*54fd6939SJiyong Park 
is_power_of_2(unsigned long x)643*54fd6939SJiyong Park static int is_power_of_2(unsigned long x)
644*54fd6939SJiyong Park {
645*54fd6939SJiyong Park 	return x && !(x & (x - 1));
646*54fd6939SJiyong Park }
647*54fd6939SJiyong Park 
get_image_align(char * arg)648*54fd6939SJiyong Park static unsigned long get_image_align(char *arg)
649*54fd6939SJiyong Park {
650*54fd6939SJiyong Park 	char *endptr;
651*54fd6939SJiyong Park 	unsigned long align;
652*54fd6939SJiyong Park 
653*54fd6939SJiyong Park 	errno = 0;
654*54fd6939SJiyong Park 	align = strtoul(arg, &endptr, 0);
655*54fd6939SJiyong Park 	if (*endptr != '\0' || !is_power_of_2(align) || errno != 0)
656*54fd6939SJiyong Park 		log_errx("Invalid alignment: %s", arg);
657*54fd6939SJiyong Park 
658*54fd6939SJiyong Park 	return align;
659*54fd6939SJiyong Park }
660*54fd6939SJiyong Park 
parse_blob_opt(char * arg,uuid_t * uuid,char * filename,size_t len)661*54fd6939SJiyong Park static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len)
662*54fd6939SJiyong Park {
663*54fd6939SJiyong Park 	char *p;
664*54fd6939SJiyong Park 
665*54fd6939SJiyong Park 	for (p = strtok(arg, ","); p != NULL; p = strtok(NULL, ",")) {
666*54fd6939SJiyong Park 		if (strncmp(p, "uuid=", strlen("uuid=")) == 0) {
667*54fd6939SJiyong Park 			p += strlen("uuid=");
668*54fd6939SJiyong Park 			uuid_from_str(uuid, p);
669*54fd6939SJiyong Park 		} else if (strncmp(p, "file=", strlen("file=")) == 0) {
670*54fd6939SJiyong Park 			p += strlen("file=");
671*54fd6939SJiyong Park 			snprintf(filename, len, "%s", p);
672*54fd6939SJiyong Park 		}
673*54fd6939SJiyong Park 	}
674*54fd6939SJiyong Park }
675*54fd6939SJiyong Park 
create_cmd(int argc,char * argv[])676*54fd6939SJiyong Park static int create_cmd(int argc, char *argv[])
677*54fd6939SJiyong Park {
678*54fd6939SJiyong Park 	struct option *opts = NULL;
679*54fd6939SJiyong Park 	size_t nr_opts = 0;
680*54fd6939SJiyong Park 	unsigned long long toc_flags = 0;
681*54fd6939SJiyong Park 	unsigned long align = 1;
682*54fd6939SJiyong Park 
683*54fd6939SJiyong Park 	if (argc < 2)
684*54fd6939SJiyong Park 		create_usage(EXIT_FAILURE);
685*54fd6939SJiyong Park 
686*54fd6939SJiyong Park 	opts = fill_common_opts(opts, &nr_opts, required_argument);
687*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
688*54fd6939SJiyong Park 	    OPT_PLAT_TOC_FLAGS);
689*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
690*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
691*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
692*54fd6939SJiyong Park 
693*54fd6939SJiyong Park 	while (1) {
694*54fd6939SJiyong Park 		int c, opt_index = 0;
695*54fd6939SJiyong Park 
696*54fd6939SJiyong Park 		c = getopt_long(argc, argv, "b:", opts, &opt_index);
697*54fd6939SJiyong Park 		if (c == -1)
698*54fd6939SJiyong Park 			break;
699*54fd6939SJiyong Park 
700*54fd6939SJiyong Park 		switch (c) {
701*54fd6939SJiyong Park 		case OPT_TOC_ENTRY: {
702*54fd6939SJiyong Park 			image_desc_t *desc;
703*54fd6939SJiyong Park 
704*54fd6939SJiyong Park 			desc = lookup_image_desc_from_opt(opts[opt_index].name);
705*54fd6939SJiyong Park 			set_image_desc_action(desc, DO_PACK, optarg);
706*54fd6939SJiyong Park 			break;
707*54fd6939SJiyong Park 		}
708*54fd6939SJiyong Park 		case OPT_PLAT_TOC_FLAGS:
709*54fd6939SJiyong Park 			parse_plat_toc_flags(optarg, &toc_flags);
710*54fd6939SJiyong Park 			break;
711*54fd6939SJiyong Park 		case OPT_ALIGN:
712*54fd6939SJiyong Park 			align = get_image_align(optarg);
713*54fd6939SJiyong Park 			break;
714*54fd6939SJiyong Park 		case 'b': {
715*54fd6939SJiyong Park 			char name[_UUID_STR_LEN + 1];
716*54fd6939SJiyong Park 			char filename[PATH_MAX] = { 0 };
717*54fd6939SJiyong Park 			uuid_t uuid = uuid_null;
718*54fd6939SJiyong Park 			image_desc_t *desc;
719*54fd6939SJiyong Park 
720*54fd6939SJiyong Park 			parse_blob_opt(optarg, &uuid,
721*54fd6939SJiyong Park 			    filename, sizeof(filename));
722*54fd6939SJiyong Park 
723*54fd6939SJiyong Park 			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
724*54fd6939SJiyong Park 			    filename[0] == '\0')
725*54fd6939SJiyong Park 				create_usage(EXIT_FAILURE);
726*54fd6939SJiyong Park 
727*54fd6939SJiyong Park 			desc = lookup_image_desc_from_uuid(&uuid);
728*54fd6939SJiyong Park 			if (desc == NULL) {
729*54fd6939SJiyong Park 				uuid_to_str(name, sizeof(name), &uuid);
730*54fd6939SJiyong Park 				desc = new_image_desc(&uuid, name, "blob");
731*54fd6939SJiyong Park 				add_image_desc(desc);
732*54fd6939SJiyong Park 			}
733*54fd6939SJiyong Park 			set_image_desc_action(desc, DO_PACK, filename);
734*54fd6939SJiyong Park 			break;
735*54fd6939SJiyong Park 		}
736*54fd6939SJiyong Park 		default:
737*54fd6939SJiyong Park 			create_usage(EXIT_FAILURE);
738*54fd6939SJiyong Park 		}
739*54fd6939SJiyong Park 	}
740*54fd6939SJiyong Park 	argc -= optind;
741*54fd6939SJiyong Park 	argv += optind;
742*54fd6939SJiyong Park 	free(opts);
743*54fd6939SJiyong Park 
744*54fd6939SJiyong Park 	if (argc == 0)
745*54fd6939SJiyong Park 		create_usage(EXIT_SUCCESS);
746*54fd6939SJiyong Park 
747*54fd6939SJiyong Park 	update_fip();
748*54fd6939SJiyong Park 
749*54fd6939SJiyong Park 	pack_images(argv[0], toc_flags, align);
750*54fd6939SJiyong Park 	return 0;
751*54fd6939SJiyong Park }
752*54fd6939SJiyong Park 
create_usage(int exit_status)753*54fd6939SJiyong Park static void create_usage(int exit_status)
754*54fd6939SJiyong Park {
755*54fd6939SJiyong Park 	toc_entry_t *toc_entry = toc_entries;
756*54fd6939SJiyong Park 
757*54fd6939SJiyong Park 	printf("fiptool create [opts] FIP_FILENAME\n");
758*54fd6939SJiyong Park 	printf("\n");
759*54fd6939SJiyong Park 	printf("Options:\n");
760*54fd6939SJiyong Park 	printf("  --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
761*54fd6939SJiyong Park 	printf("  --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n");
762*54fd6939SJiyong Park 	printf("  --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
763*54fd6939SJiyong Park 	printf("\n");
764*54fd6939SJiyong Park 	printf("Specific images are packed with the following options:\n");
765*54fd6939SJiyong Park 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
766*54fd6939SJiyong Park 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
767*54fd6939SJiyong Park 		    toc_entry->name);
768*54fd6939SJiyong Park #ifdef PLAT_DEF_FIP_UUID
769*54fd6939SJiyong Park 	toc_entry = plat_def_toc_entries;
770*54fd6939SJiyong Park 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
771*54fd6939SJiyong Park 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
772*54fd6939SJiyong Park 		    toc_entry->name);
773*54fd6939SJiyong Park #endif
774*54fd6939SJiyong Park 	exit(exit_status);
775*54fd6939SJiyong Park }
776*54fd6939SJiyong Park 
update_cmd(int argc,char * argv[])777*54fd6939SJiyong Park static int update_cmd(int argc, char *argv[])
778*54fd6939SJiyong Park {
779*54fd6939SJiyong Park 	struct option *opts = NULL;
780*54fd6939SJiyong Park 	size_t nr_opts = 0;
781*54fd6939SJiyong Park 	char outfile[PATH_MAX] = { 0 };
782*54fd6939SJiyong Park 	fip_toc_header_t toc_header = { 0 };
783*54fd6939SJiyong Park 	unsigned long long toc_flags = 0;
784*54fd6939SJiyong Park 	unsigned long align = 1;
785*54fd6939SJiyong Park 	int pflag = 0;
786*54fd6939SJiyong Park 
787*54fd6939SJiyong Park 	if (argc < 2)
788*54fd6939SJiyong Park 		update_usage(EXIT_FAILURE);
789*54fd6939SJiyong Park 
790*54fd6939SJiyong Park 	opts = fill_common_opts(opts, &nr_opts, required_argument);
791*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
792*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
793*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
794*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument,
795*54fd6939SJiyong Park 	    OPT_PLAT_TOC_FLAGS);
796*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
797*54fd6939SJiyong Park 
798*54fd6939SJiyong Park 	while (1) {
799*54fd6939SJiyong Park 		int c, opt_index = 0;
800*54fd6939SJiyong Park 
801*54fd6939SJiyong Park 		c = getopt_long(argc, argv, "b:o:", opts, &opt_index);
802*54fd6939SJiyong Park 		if (c == -1)
803*54fd6939SJiyong Park 			break;
804*54fd6939SJiyong Park 
805*54fd6939SJiyong Park 		switch (c) {
806*54fd6939SJiyong Park 		case OPT_TOC_ENTRY: {
807*54fd6939SJiyong Park 			image_desc_t *desc;
808*54fd6939SJiyong Park 
809*54fd6939SJiyong Park 			desc = lookup_image_desc_from_opt(opts[opt_index].name);
810*54fd6939SJiyong Park 			set_image_desc_action(desc, DO_PACK, optarg);
811*54fd6939SJiyong Park 			break;
812*54fd6939SJiyong Park 		}
813*54fd6939SJiyong Park 		case OPT_PLAT_TOC_FLAGS:
814*54fd6939SJiyong Park 			parse_plat_toc_flags(optarg, &toc_flags);
815*54fd6939SJiyong Park 			pflag = 1;
816*54fd6939SJiyong Park 			break;
817*54fd6939SJiyong Park 		case 'b': {
818*54fd6939SJiyong Park 			char name[_UUID_STR_LEN + 1];
819*54fd6939SJiyong Park 			char filename[PATH_MAX] = { 0 };
820*54fd6939SJiyong Park 			uuid_t uuid = uuid_null;
821*54fd6939SJiyong Park 			image_desc_t *desc;
822*54fd6939SJiyong Park 
823*54fd6939SJiyong Park 			parse_blob_opt(optarg, &uuid,
824*54fd6939SJiyong Park 			    filename, sizeof(filename));
825*54fd6939SJiyong Park 
826*54fd6939SJiyong Park 			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
827*54fd6939SJiyong Park 			    filename[0] == '\0')
828*54fd6939SJiyong Park 				update_usage(EXIT_FAILURE);
829*54fd6939SJiyong Park 
830*54fd6939SJiyong Park 			desc = lookup_image_desc_from_uuid(&uuid);
831*54fd6939SJiyong Park 			if (desc == NULL) {
832*54fd6939SJiyong Park 				uuid_to_str(name, sizeof(name), &uuid);
833*54fd6939SJiyong Park 				desc = new_image_desc(&uuid, name, "blob");
834*54fd6939SJiyong Park 				add_image_desc(desc);
835*54fd6939SJiyong Park 			}
836*54fd6939SJiyong Park 			set_image_desc_action(desc, DO_PACK, filename);
837*54fd6939SJiyong Park 			break;
838*54fd6939SJiyong Park 		}
839*54fd6939SJiyong Park 		case OPT_ALIGN:
840*54fd6939SJiyong Park 			align = get_image_align(optarg);
841*54fd6939SJiyong Park 			break;
842*54fd6939SJiyong Park 		case 'o':
843*54fd6939SJiyong Park 			snprintf(outfile, sizeof(outfile), "%s", optarg);
844*54fd6939SJiyong Park 			break;
845*54fd6939SJiyong Park 		default:
846*54fd6939SJiyong Park 			update_usage(EXIT_FAILURE);
847*54fd6939SJiyong Park 		}
848*54fd6939SJiyong Park 	}
849*54fd6939SJiyong Park 	argc -= optind;
850*54fd6939SJiyong Park 	argv += optind;
851*54fd6939SJiyong Park 	free(opts);
852*54fd6939SJiyong Park 
853*54fd6939SJiyong Park 	if (argc == 0)
854*54fd6939SJiyong Park 		update_usage(EXIT_SUCCESS);
855*54fd6939SJiyong Park 
856*54fd6939SJiyong Park 	if (outfile[0] == '\0')
857*54fd6939SJiyong Park 		snprintf(outfile, sizeof(outfile), "%s", argv[0]);
858*54fd6939SJiyong Park 
859*54fd6939SJiyong Park 	if (access(argv[0], F_OK) == 0)
860*54fd6939SJiyong Park 		parse_fip(argv[0], &toc_header);
861*54fd6939SJiyong Park 
862*54fd6939SJiyong Park 	if (pflag)
863*54fd6939SJiyong Park 		toc_header.flags &= ~(0xffffULL << 32);
864*54fd6939SJiyong Park 	toc_flags = (toc_header.flags |= toc_flags);
865*54fd6939SJiyong Park 
866*54fd6939SJiyong Park 	update_fip();
867*54fd6939SJiyong Park 
868*54fd6939SJiyong Park 	pack_images(outfile, toc_flags, align);
869*54fd6939SJiyong Park 	return 0;
870*54fd6939SJiyong Park }
871*54fd6939SJiyong Park 
update_usage(int exit_status)872*54fd6939SJiyong Park static void update_usage(int exit_status)
873*54fd6939SJiyong Park {
874*54fd6939SJiyong Park 	toc_entry_t *toc_entry = toc_entries;
875*54fd6939SJiyong Park 
876*54fd6939SJiyong Park 	printf("fiptool update [opts] FIP_FILENAME\n");
877*54fd6939SJiyong Park 	printf("\n");
878*54fd6939SJiyong Park 	printf("Options:\n");
879*54fd6939SJiyong Park 	printf("  --align <value>\t\tEach image is aligned to <value> (default: 1).\n");
880*54fd6939SJiyong Park 	printf("  --blob uuid=...,file=...\tAdd or update an image with the given UUID pointed to by file.\n");
881*54fd6939SJiyong Park 	printf("  --out FIP_FILENAME\t\tSet an alternative output FIP file.\n");
882*54fd6939SJiyong Park 	printf("  --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n");
883*54fd6939SJiyong Park 	printf("\n");
884*54fd6939SJiyong Park 	printf("Specific images are packed with the following options:\n");
885*54fd6939SJiyong Park 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
886*54fd6939SJiyong Park 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
887*54fd6939SJiyong Park 		    toc_entry->name);
888*54fd6939SJiyong Park #ifdef PLAT_DEF_FIP_UUID
889*54fd6939SJiyong Park 	toc_entry = plat_def_toc_entries;
890*54fd6939SJiyong Park 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
891*54fd6939SJiyong Park 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
892*54fd6939SJiyong Park 		    toc_entry->name);
893*54fd6939SJiyong Park #endif
894*54fd6939SJiyong Park 	exit(exit_status);
895*54fd6939SJiyong Park }
896*54fd6939SJiyong Park 
unpack_cmd(int argc,char * argv[])897*54fd6939SJiyong Park static int unpack_cmd(int argc, char *argv[])
898*54fd6939SJiyong Park {
899*54fd6939SJiyong Park 	struct option *opts = NULL;
900*54fd6939SJiyong Park 	size_t nr_opts = 0;
901*54fd6939SJiyong Park 	char outdir[PATH_MAX] = { 0 };
902*54fd6939SJiyong Park 	image_desc_t *desc;
903*54fd6939SJiyong Park 	int fflag = 0;
904*54fd6939SJiyong Park 	int unpack_all = 1;
905*54fd6939SJiyong Park 
906*54fd6939SJiyong Park 	if (argc < 2)
907*54fd6939SJiyong Park 		unpack_usage(EXIT_FAILURE);
908*54fd6939SJiyong Park 
909*54fd6939SJiyong Park 	opts = fill_common_opts(opts, &nr_opts, required_argument);
910*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
911*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
912*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
913*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
914*54fd6939SJiyong Park 
915*54fd6939SJiyong Park 	while (1) {
916*54fd6939SJiyong Park 		int c, opt_index = 0;
917*54fd6939SJiyong Park 
918*54fd6939SJiyong Park 		c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
919*54fd6939SJiyong Park 		if (c == -1)
920*54fd6939SJiyong Park 			break;
921*54fd6939SJiyong Park 
922*54fd6939SJiyong Park 		switch (c) {
923*54fd6939SJiyong Park 		case OPT_TOC_ENTRY: {
924*54fd6939SJiyong Park 			image_desc_t *desc;
925*54fd6939SJiyong Park 
926*54fd6939SJiyong Park 			desc = lookup_image_desc_from_opt(opts[opt_index].name);
927*54fd6939SJiyong Park 			set_image_desc_action(desc, DO_UNPACK, optarg);
928*54fd6939SJiyong Park 			unpack_all = 0;
929*54fd6939SJiyong Park 			break;
930*54fd6939SJiyong Park 		}
931*54fd6939SJiyong Park 		case 'b': {
932*54fd6939SJiyong Park 			char name[_UUID_STR_LEN + 1];
933*54fd6939SJiyong Park 			char filename[PATH_MAX] = { 0 };
934*54fd6939SJiyong Park 			uuid_t uuid = uuid_null;
935*54fd6939SJiyong Park 			image_desc_t *desc;
936*54fd6939SJiyong Park 
937*54fd6939SJiyong Park 			parse_blob_opt(optarg, &uuid,
938*54fd6939SJiyong Park 			    filename, sizeof(filename));
939*54fd6939SJiyong Park 
940*54fd6939SJiyong Park 			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
941*54fd6939SJiyong Park 			    filename[0] == '\0')
942*54fd6939SJiyong Park 				unpack_usage(EXIT_FAILURE);
943*54fd6939SJiyong Park 
944*54fd6939SJiyong Park 			desc = lookup_image_desc_from_uuid(&uuid);
945*54fd6939SJiyong Park 			if (desc == NULL) {
946*54fd6939SJiyong Park 				uuid_to_str(name, sizeof(name), &uuid);
947*54fd6939SJiyong Park 				desc = new_image_desc(&uuid, name, "blob");
948*54fd6939SJiyong Park 				add_image_desc(desc);
949*54fd6939SJiyong Park 			}
950*54fd6939SJiyong Park 			set_image_desc_action(desc, DO_UNPACK, filename);
951*54fd6939SJiyong Park 			unpack_all = 0;
952*54fd6939SJiyong Park 			break;
953*54fd6939SJiyong Park 		}
954*54fd6939SJiyong Park 		case 'f':
955*54fd6939SJiyong Park 			fflag = 1;
956*54fd6939SJiyong Park 			break;
957*54fd6939SJiyong Park 		case 'o':
958*54fd6939SJiyong Park 			snprintf(outdir, sizeof(outdir), "%s", optarg);
959*54fd6939SJiyong Park 			break;
960*54fd6939SJiyong Park 		default:
961*54fd6939SJiyong Park 			unpack_usage(EXIT_FAILURE);
962*54fd6939SJiyong Park 		}
963*54fd6939SJiyong Park 	}
964*54fd6939SJiyong Park 	argc -= optind;
965*54fd6939SJiyong Park 	argv += optind;
966*54fd6939SJiyong Park 	free(opts);
967*54fd6939SJiyong Park 
968*54fd6939SJiyong Park 	if (argc == 0)
969*54fd6939SJiyong Park 		unpack_usage(EXIT_SUCCESS);
970*54fd6939SJiyong Park 
971*54fd6939SJiyong Park 	parse_fip(argv[0], NULL);
972*54fd6939SJiyong Park 
973*54fd6939SJiyong Park 	if (outdir[0] != '\0')
974*54fd6939SJiyong Park 		if (chdir(outdir) == -1)
975*54fd6939SJiyong Park 			log_err("chdir %s", outdir);
976*54fd6939SJiyong Park 
977*54fd6939SJiyong Park 	/* Unpack all specified images. */
978*54fd6939SJiyong Park 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
979*54fd6939SJiyong Park 		char file[PATH_MAX];
980*54fd6939SJiyong Park 		image_t *image = desc->image;
981*54fd6939SJiyong Park 
982*54fd6939SJiyong Park 		if (!unpack_all && desc->action != DO_UNPACK)
983*54fd6939SJiyong Park 			continue;
984*54fd6939SJiyong Park 
985*54fd6939SJiyong Park 		/* Build filename. */
986*54fd6939SJiyong Park 		if (desc->action_arg == NULL)
987*54fd6939SJiyong Park 			snprintf(file, sizeof(file), "%s.bin",
988*54fd6939SJiyong Park 			    desc->cmdline_name);
989*54fd6939SJiyong Park 		else
990*54fd6939SJiyong Park 			snprintf(file, sizeof(file), "%s",
991*54fd6939SJiyong Park 			    desc->action_arg);
992*54fd6939SJiyong Park 
993*54fd6939SJiyong Park 		if (image == NULL) {
994*54fd6939SJiyong Park 			if (!unpack_all)
995*54fd6939SJiyong Park 				log_warnx("%s does not exist in %s",
996*54fd6939SJiyong Park 				    file, argv[0]);
997*54fd6939SJiyong Park 			continue;
998*54fd6939SJiyong Park 		}
999*54fd6939SJiyong Park 
1000*54fd6939SJiyong Park 		if (access(file, F_OK) != 0 || fflag) {
1001*54fd6939SJiyong Park 			if (verbose)
1002*54fd6939SJiyong Park 				log_dbgx("Unpacking %s", file);
1003*54fd6939SJiyong Park 			write_image_to_file(image, file);
1004*54fd6939SJiyong Park 		} else {
1005*54fd6939SJiyong Park 			log_warnx("File %s already exists, use --force to overwrite it",
1006*54fd6939SJiyong Park 			    file);
1007*54fd6939SJiyong Park 		}
1008*54fd6939SJiyong Park 	}
1009*54fd6939SJiyong Park 
1010*54fd6939SJiyong Park 	return 0;
1011*54fd6939SJiyong Park }
1012*54fd6939SJiyong Park 
unpack_usage(int exit_status)1013*54fd6939SJiyong Park static void unpack_usage(int exit_status)
1014*54fd6939SJiyong Park {
1015*54fd6939SJiyong Park 	toc_entry_t *toc_entry = toc_entries;
1016*54fd6939SJiyong Park 
1017*54fd6939SJiyong Park 	printf("fiptool unpack [opts] FIP_FILENAME\n");
1018*54fd6939SJiyong Park 	printf("\n");
1019*54fd6939SJiyong Park 	printf("Options:\n");
1020*54fd6939SJiyong Park 	printf("  --blob uuid=...,file=...\tUnpack an image with the given UUID to file.\n");
1021*54fd6939SJiyong Park 	printf("  --force\t\t\tIf the output file already exists, use --force to overwrite it.\n");
1022*54fd6939SJiyong Park 	printf("  --out path\t\t\tSet the output directory path.\n");
1023*54fd6939SJiyong Park 	printf("\n");
1024*54fd6939SJiyong Park 	printf("Specific images are unpacked with the following options:\n");
1025*54fd6939SJiyong Park 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
1026*54fd6939SJiyong Park 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
1027*54fd6939SJiyong Park 		    toc_entry->name);
1028*54fd6939SJiyong Park #ifdef PLAT_DEF_FIP_UUID
1029*54fd6939SJiyong Park 	toc_entry = plat_def_toc_entries;
1030*54fd6939SJiyong Park 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
1031*54fd6939SJiyong Park 		printf("  --%-16s FILENAME\t%s\n", toc_entry->cmdline_name,
1032*54fd6939SJiyong Park 		    toc_entry->name);
1033*54fd6939SJiyong Park #endif
1034*54fd6939SJiyong Park 	printf("\n");
1035*54fd6939SJiyong Park 	printf("If no options are provided, all images will be unpacked.\n");
1036*54fd6939SJiyong Park 	exit(exit_status);
1037*54fd6939SJiyong Park }
1038*54fd6939SJiyong Park 
remove_cmd(int argc,char * argv[])1039*54fd6939SJiyong Park static int remove_cmd(int argc, char *argv[])
1040*54fd6939SJiyong Park {
1041*54fd6939SJiyong Park 	struct option *opts = NULL;
1042*54fd6939SJiyong Park 	size_t nr_opts = 0;
1043*54fd6939SJiyong Park 	char outfile[PATH_MAX] = { 0 };
1044*54fd6939SJiyong Park 	fip_toc_header_t toc_header;
1045*54fd6939SJiyong Park 	image_desc_t *desc;
1046*54fd6939SJiyong Park 	unsigned long align = 1;
1047*54fd6939SJiyong Park 	int fflag = 0;
1048*54fd6939SJiyong Park 
1049*54fd6939SJiyong Park 	if (argc < 2)
1050*54fd6939SJiyong Park 		remove_usage(EXIT_FAILURE);
1051*54fd6939SJiyong Park 
1052*54fd6939SJiyong Park 	opts = fill_common_opts(opts, &nr_opts, no_argument);
1053*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN);
1054*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b');
1055*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "force", no_argument, 'f');
1056*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, "out", required_argument, 'o');
1057*54fd6939SJiyong Park 	opts = add_opt(opts, &nr_opts, NULL, 0, 0);
1058*54fd6939SJiyong Park 
1059*54fd6939SJiyong Park 	while (1) {
1060*54fd6939SJiyong Park 		int c, opt_index = 0;
1061*54fd6939SJiyong Park 
1062*54fd6939SJiyong Park 		c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
1063*54fd6939SJiyong Park 		if (c == -1)
1064*54fd6939SJiyong Park 			break;
1065*54fd6939SJiyong Park 
1066*54fd6939SJiyong Park 		switch (c) {
1067*54fd6939SJiyong Park 		case OPT_TOC_ENTRY: {
1068*54fd6939SJiyong Park 			image_desc_t *desc;
1069*54fd6939SJiyong Park 
1070*54fd6939SJiyong Park 			desc = lookup_image_desc_from_opt(opts[opt_index].name);
1071*54fd6939SJiyong Park 			set_image_desc_action(desc, DO_REMOVE, NULL);
1072*54fd6939SJiyong Park 			break;
1073*54fd6939SJiyong Park 		}
1074*54fd6939SJiyong Park 		case OPT_ALIGN:
1075*54fd6939SJiyong Park 			align = get_image_align(optarg);
1076*54fd6939SJiyong Park 			break;
1077*54fd6939SJiyong Park 		case 'b': {
1078*54fd6939SJiyong Park 			char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
1079*54fd6939SJiyong Park 			uuid_t uuid = uuid_null;
1080*54fd6939SJiyong Park 			image_desc_t *desc;
1081*54fd6939SJiyong Park 
1082*54fd6939SJiyong Park 			parse_blob_opt(optarg, &uuid,
1083*54fd6939SJiyong Park 			    filename, sizeof(filename));
1084*54fd6939SJiyong Park 
1085*54fd6939SJiyong Park 			if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0)
1086*54fd6939SJiyong Park 				remove_usage(EXIT_FAILURE);
1087*54fd6939SJiyong Park 
1088*54fd6939SJiyong Park 			desc = lookup_image_desc_from_uuid(&uuid);
1089*54fd6939SJiyong Park 			if (desc == NULL) {
1090*54fd6939SJiyong Park 				uuid_to_str(name, sizeof(name), &uuid);
1091*54fd6939SJiyong Park 				desc = new_image_desc(&uuid, name, "blob");
1092*54fd6939SJiyong Park 				add_image_desc(desc);
1093*54fd6939SJiyong Park 			}
1094*54fd6939SJiyong Park 			set_image_desc_action(desc, DO_REMOVE, NULL);
1095*54fd6939SJiyong Park 			break;
1096*54fd6939SJiyong Park 		}
1097*54fd6939SJiyong Park 		case 'f':
1098*54fd6939SJiyong Park 			fflag = 1;
1099*54fd6939SJiyong Park 			break;
1100*54fd6939SJiyong Park 		case 'o':
1101*54fd6939SJiyong Park 			snprintf(outfile, sizeof(outfile), "%s", optarg);
1102*54fd6939SJiyong Park 			break;
1103*54fd6939SJiyong Park 		default:
1104*54fd6939SJiyong Park 			remove_usage(EXIT_FAILURE);
1105*54fd6939SJiyong Park 		}
1106*54fd6939SJiyong Park 	}
1107*54fd6939SJiyong Park 	argc -= optind;
1108*54fd6939SJiyong Park 	argv += optind;
1109*54fd6939SJiyong Park 	free(opts);
1110*54fd6939SJiyong Park 
1111*54fd6939SJiyong Park 	if (argc == 0)
1112*54fd6939SJiyong Park 		remove_usage(EXIT_SUCCESS);
1113*54fd6939SJiyong Park 
1114*54fd6939SJiyong Park 	if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag)
1115*54fd6939SJiyong Park 		log_errx("File %s already exists, use --force to overwrite it",
1116*54fd6939SJiyong Park 		    outfile);
1117*54fd6939SJiyong Park 
1118*54fd6939SJiyong Park 	if (outfile[0] == '\0')
1119*54fd6939SJiyong Park 		snprintf(outfile, sizeof(outfile), "%s", argv[0]);
1120*54fd6939SJiyong Park 
1121*54fd6939SJiyong Park 	parse_fip(argv[0], &toc_header);
1122*54fd6939SJiyong Park 
1123*54fd6939SJiyong Park 	for (desc = image_desc_head; desc != NULL; desc = desc->next) {
1124*54fd6939SJiyong Park 		if (desc->action != DO_REMOVE)
1125*54fd6939SJiyong Park 			continue;
1126*54fd6939SJiyong Park 
1127*54fd6939SJiyong Park 		if (desc->image != NULL) {
1128*54fd6939SJiyong Park 			if (verbose)
1129*54fd6939SJiyong Park 				log_dbgx("Removing %s",
1130*54fd6939SJiyong Park 				    desc->cmdline_name);
1131*54fd6939SJiyong Park 			free(desc->image);
1132*54fd6939SJiyong Park 			desc->image = NULL;
1133*54fd6939SJiyong Park 		} else {
1134*54fd6939SJiyong Park 			log_warnx("%s does not exist in %s",
1135*54fd6939SJiyong Park 			    desc->cmdline_name, argv[0]);
1136*54fd6939SJiyong Park 		}
1137*54fd6939SJiyong Park 	}
1138*54fd6939SJiyong Park 
1139*54fd6939SJiyong Park 	pack_images(outfile, toc_header.flags, align);
1140*54fd6939SJiyong Park 	return 0;
1141*54fd6939SJiyong Park }
1142*54fd6939SJiyong Park 
remove_usage(int exit_status)1143*54fd6939SJiyong Park static void remove_usage(int exit_status)
1144*54fd6939SJiyong Park {
1145*54fd6939SJiyong Park 	toc_entry_t *toc_entry = toc_entries;
1146*54fd6939SJiyong Park 
1147*54fd6939SJiyong Park 	printf("fiptool remove [opts] FIP_FILENAME\n");
1148*54fd6939SJiyong Park 	printf("\n");
1149*54fd6939SJiyong Park 	printf("Options:\n");
1150*54fd6939SJiyong Park 	printf("  --align <value>\tEach image is aligned to <value> (default: 1).\n");
1151*54fd6939SJiyong Park 	printf("  --blob uuid=...\tRemove an image with the given UUID.\n");
1152*54fd6939SJiyong Park 	printf("  --force\t\tIf the output FIP file already exists, use --force to overwrite it.\n");
1153*54fd6939SJiyong Park 	printf("  --out FIP_FILENAME\tSet an alternative output FIP file.\n");
1154*54fd6939SJiyong Park 	printf("\n");
1155*54fd6939SJiyong Park 	printf("Specific images are removed with the following options:\n");
1156*54fd6939SJiyong Park 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
1157*54fd6939SJiyong Park 		printf("  --%-16s\t%s\n", toc_entry->cmdline_name,
1158*54fd6939SJiyong Park 		    toc_entry->name);
1159*54fd6939SJiyong Park #ifdef PLAT_DEF_FIP_UUID
1160*54fd6939SJiyong Park 	toc_entry = plat_def_toc_entries;
1161*54fd6939SJiyong Park 	for (; toc_entry->cmdline_name != NULL; toc_entry++)
1162*54fd6939SJiyong Park 		printf("  --%-16s\t%s\n", toc_entry->cmdline_name,
1163*54fd6939SJiyong Park 		    toc_entry->name);
1164*54fd6939SJiyong Park #endif
1165*54fd6939SJiyong Park 	exit(exit_status);
1166*54fd6939SJiyong Park }
1167*54fd6939SJiyong Park 
version_cmd(int argc,char * argv[])1168*54fd6939SJiyong Park static int version_cmd(int argc, char *argv[])
1169*54fd6939SJiyong Park {
1170*54fd6939SJiyong Park #ifdef VERSION
1171*54fd6939SJiyong Park 	puts(VERSION);
1172*54fd6939SJiyong Park #else
1173*54fd6939SJiyong Park 	/* If built from fiptool directory, VERSION is not set. */
1174*54fd6939SJiyong Park 	puts("Unknown version");
1175*54fd6939SJiyong Park #endif
1176*54fd6939SJiyong Park 	return 0;
1177*54fd6939SJiyong Park }
1178*54fd6939SJiyong Park 
version_usage(int exit_status)1179*54fd6939SJiyong Park static void version_usage(int exit_status)
1180*54fd6939SJiyong Park {
1181*54fd6939SJiyong Park 	printf("fiptool version\n");
1182*54fd6939SJiyong Park 	exit(exit_status);
1183*54fd6939SJiyong Park }
1184*54fd6939SJiyong Park 
help_cmd(int argc,char * argv[])1185*54fd6939SJiyong Park static int help_cmd(int argc, char *argv[])
1186*54fd6939SJiyong Park {
1187*54fd6939SJiyong Park 	int i;
1188*54fd6939SJiyong Park 
1189*54fd6939SJiyong Park 	if (argc < 2)
1190*54fd6939SJiyong Park 		usage();
1191*54fd6939SJiyong Park 	argc--, argv++;
1192*54fd6939SJiyong Park 
1193*54fd6939SJiyong Park 	for (i = 0; i < NELEM(cmds); i++) {
1194*54fd6939SJiyong Park 		if (strcmp(cmds[i].name, argv[0]) == 0 &&
1195*54fd6939SJiyong Park 		    cmds[i].usage != NULL)
1196*54fd6939SJiyong Park 			cmds[i].usage(EXIT_SUCCESS);
1197*54fd6939SJiyong Park 	}
1198*54fd6939SJiyong Park 	if (i == NELEM(cmds))
1199*54fd6939SJiyong Park 		printf("No help for subcommand '%s'\n", argv[0]);
1200*54fd6939SJiyong Park 	return 0;
1201*54fd6939SJiyong Park }
1202*54fd6939SJiyong Park 
usage(void)1203*54fd6939SJiyong Park static void usage(void)
1204*54fd6939SJiyong Park {
1205*54fd6939SJiyong Park 	printf("usage: fiptool [--verbose] <command> [<args>]\n");
1206*54fd6939SJiyong Park 	printf("Global options supported:\n");
1207*54fd6939SJiyong Park 	printf("  --verbose\tEnable verbose output for all commands.\n");
1208*54fd6939SJiyong Park 	printf("\n");
1209*54fd6939SJiyong Park 	printf("Commands supported:\n");
1210*54fd6939SJiyong Park 	printf("  info\t\tList images contained in FIP.\n");
1211*54fd6939SJiyong Park 	printf("  create\tCreate a new FIP with the given images.\n");
1212*54fd6939SJiyong Park 	printf("  update\tUpdate an existing FIP with the given images.\n");
1213*54fd6939SJiyong Park 	printf("  unpack\tUnpack images from FIP.\n");
1214*54fd6939SJiyong Park 	printf("  remove\tRemove images from FIP.\n");
1215*54fd6939SJiyong Park 	printf("  version\tShow fiptool version.\n");
1216*54fd6939SJiyong Park 	printf("  help\t\tShow help for given command.\n");
1217*54fd6939SJiyong Park 	exit(EXIT_SUCCESS);
1218*54fd6939SJiyong Park }
1219*54fd6939SJiyong Park 
main(int argc,char * argv[])1220*54fd6939SJiyong Park int main(int argc, char *argv[])
1221*54fd6939SJiyong Park {
1222*54fd6939SJiyong Park 	int i, ret = 0;
1223*54fd6939SJiyong Park 
1224*54fd6939SJiyong Park 	while (1) {
1225*54fd6939SJiyong Park 		int c, opt_index = 0;
1226*54fd6939SJiyong Park 		static struct option opts[] = {
1227*54fd6939SJiyong Park 			{ "verbose", no_argument, NULL, 'v' },
1228*54fd6939SJiyong Park 			{ NULL, no_argument, NULL, 0 }
1229*54fd6939SJiyong Park 		};
1230*54fd6939SJiyong Park 
1231*54fd6939SJiyong Park 		/*
1232*54fd6939SJiyong Park 		 * Set POSIX mode so getopt stops at the first non-option
1233*54fd6939SJiyong Park 		 * which is the subcommand.
1234*54fd6939SJiyong Park 		 */
1235*54fd6939SJiyong Park 		c = getopt_long(argc, argv, "+v", opts, &opt_index);
1236*54fd6939SJiyong Park 		if (c == -1)
1237*54fd6939SJiyong Park 			break;
1238*54fd6939SJiyong Park 
1239*54fd6939SJiyong Park 		switch (c) {
1240*54fd6939SJiyong Park 		case 'v':
1241*54fd6939SJiyong Park 			verbose = 1;
1242*54fd6939SJiyong Park 			break;
1243*54fd6939SJiyong Park 		default:
1244*54fd6939SJiyong Park 			usage();
1245*54fd6939SJiyong Park 		}
1246*54fd6939SJiyong Park 	}
1247*54fd6939SJiyong Park 	argc -= optind;
1248*54fd6939SJiyong Park 	argv += optind;
1249*54fd6939SJiyong Park 	/* Reset optind for subsequent getopt processing. */
1250*54fd6939SJiyong Park 	optind = 0;
1251*54fd6939SJiyong Park 
1252*54fd6939SJiyong Park 	if (argc == 0)
1253*54fd6939SJiyong Park 		usage();
1254*54fd6939SJiyong Park 
1255*54fd6939SJiyong Park 	fill_image_descs();
1256*54fd6939SJiyong Park 	for (i = 0; i < NELEM(cmds); i++) {
1257*54fd6939SJiyong Park 		if (strcmp(cmds[i].name, argv[0]) == 0) {
1258*54fd6939SJiyong Park 			ret = cmds[i].handler(argc, argv);
1259*54fd6939SJiyong Park 			break;
1260*54fd6939SJiyong Park 		}
1261*54fd6939SJiyong Park 	}
1262*54fd6939SJiyong Park 	if (i == NELEM(cmds))
1263*54fd6939SJiyong Park 		usage();
1264*54fd6939SJiyong Park 	free_image_descs();
1265*54fd6939SJiyong Park 	return ret;
1266*54fd6939SJiyong Park }
1267