Home | History | Annotate | Download | only in fip_create
      1 /*
      2  * Copyright (c) 2014, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are met:
      6  *
      7  * Redistributions of source code must retain the above copyright notice, this
      8  * list of conditions and the following disclaimer.
      9  *
     10  * Redistributions in binary form must reproduce the above copyright notice,
     11  * this list of conditions and the following disclaimer in the documentation
     12  * and/or other materials provided with the distribution.
     13  *
     14  * Neither the name of ARM nor the names of its contributors may be used
     15  * to endorse or promote products derived from this software without specific
     16  * prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
     22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     28  * POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include <errno.h>
     32 #include <getopt.h> /* getopt_long() is a GNU extention */
     33 #include <stdbool.h>
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <sys/stat.h>
     38 #include "fip_create.h"
     39 #include "firmware_image_package.h"
     40 
     41 /* Values returned by getopt() as part of the command line parsing */
     42 #define OPT_TOC_ENTRY 0
     43 #define OPT_DUMP 1
     44 #define OPT_HELP 2
     45 
     46 file_info_t files[MAX_FILES];
     47 unsigned file_info_count = 0;
     48 uuid_t uuid_null = {0};
     49 
     50 /*
     51  * TODO: Add ability to specify and flag different file types.
     52  * Add flags to the toc_entry?
     53  * const char* format_type_str[] = { "RAW", "ELF", "PIC" };
     54  */
     55 
     56 /* The images used depends on the platform. */
     57 static entry_lookup_list_t toc_entry_lookup_list[] = {
     58 	{ "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2,
     59 	  "bl2", NULL, FLAG_FILENAME },
     60 	{ "SCP Firmware BL3-0", UUID_SCP_FIRMWARE_BL30,
     61 	  "bl30", NULL, FLAG_FILENAME},
     62 	{ "EL3 Runtime Firmware BL3-1", UUID_EL3_RUNTIME_FIRMWARE_BL31,
     63 	  "bl31", NULL, FLAG_FILENAME},
     64 	{ "Secure Payload BL3-2 (Trusted OS)", UUID_SECURE_PAYLOAD_BL32,
     65 	  "bl32", NULL, FLAG_FILENAME},
     66 	{ "Non-Trusted Firmware BL3-3", UUID_NON_TRUSTED_FIRMWARE_BL33,
     67 	  "bl33", NULL, FLAG_FILENAME},
     68 	/* Key Certificates */
     69 	{ "Root Of Trust key certificate", UUID_ROT_KEY_CERT,
     70 	  "rot-cert", NULL, FLAG_FILENAME },
     71 	{ "Trusted key certificate", UUID_TRUSTED_KEY_CERT,
     72 	  "trusted-key-cert", NULL, FLAG_FILENAME},
     73 	{ "SCP Firmware BL3-0 key certificate", UUID_SCP_FIRMWARE_BL30_KEY_CERT,
     74 	  "bl30-key-cert", NULL, FLAG_FILENAME},
     75 	{ "EL3 Runtime Firmware BL3-1 key certificate", UUID_EL3_RUNTIME_FIRMWARE_BL31_KEY_CERT,
     76 	  "bl31-key-cert", NULL, FLAG_FILENAME},
     77 	{ "Secure Payload BL3-2 (Trusted OS) key certificate", UUID_SECURE_PAYLOAD_BL32_KEY_CERT,
     78 	  "bl32-key-cert", NULL, FLAG_FILENAME},
     79 	{ "Non-Trusted Firmware BL3-3 key certificate", UUID_NON_TRUSTED_FIRMWARE_BL33_KEY_CERT,
     80 	  "bl33-key-cert", NULL, FLAG_FILENAME},
     81 	/* Content certificates */
     82 	{ "Trusted Boot Firmware BL2 certificate", UUID_TRUSTED_BOOT_FIRMWARE_BL2_CERT,
     83 	  "bl2-cert", NULL, FLAG_FILENAME },
     84 	{ "SCP Firmware BL3-0 certificate", UUID_SCP_FIRMWARE_BL30_CERT,
     85 	  "bl30-cert", NULL, FLAG_FILENAME},
     86 	{ "EL3 Runtime Firmware BL3-1 certificate", UUID_EL3_RUNTIME_FIRMWARE_BL31_CERT,
     87 	  "bl31-cert", NULL, FLAG_FILENAME},
     88 	{ "Secure Payload BL3-2 (Trusted OS) certificate", UUID_SECURE_PAYLOAD_BL32_CERT,
     89 	  "bl32-cert", NULL, FLAG_FILENAME},
     90 	{ "Non-Trusted Firmware BL3-3 certificate", UUID_NON_TRUSTED_FIRMWARE_BL33_CERT,
     91 	  "bl33-cert", NULL, FLAG_FILENAME},
     92 	{ NULL, {0}, 0 }
     93 };
     94 
     95 
     96 /* Return 0 for equal uuids */
     97 static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2)
     98 {
     99 	return memcmp(uuid1, uuid2, sizeof(uuid_t));
    100 }
    101 
    102 
    103 static inline void copy_uuid(uuid_t *to_uuid, const uuid_t *from_uuid)
    104 {
    105 	memcpy(to_uuid, from_uuid, sizeof(uuid_t));
    106 }
    107 
    108 
    109 static void print_usage(void)
    110 {
    111 	entry_lookup_list_t *entry = toc_entry_lookup_list;
    112 
    113 	printf("Usage: fip_create [options] FIP_FILENAME\n\n");
    114 	printf("\tThis tool is used to create a Firmware Image Package.\n\n");
    115 	printf("Options:\n");
    116 	printf("\t--help: Print this help message and exit\n");
    117 	printf("\t--dump: Print contents of FIP\n\n");
    118 	printf("\tComponents that can be added/updated:\n");
    119 	for (; entry->command_line_name != NULL; entry++) {
    120 		printf("\t--%s%s\t\t%s",
    121 		       entry->command_line_name,
    122 		       (entry->flags & FLAG_FILENAME) ? " FILENAME" : "",
    123 		       entry->name);
    124 		printf("\n");
    125 	}
    126 }
    127 
    128 
    129 static entry_lookup_list_t *get_entry_lookup_from_uuid(const uuid_t *uuid)
    130 {
    131 	unsigned int lookup_index = 0;
    132 
    133 	while (toc_entry_lookup_list[lookup_index].command_line_name != NULL) {
    134 		if (compare_uuids(&toc_entry_lookup_list[lookup_index].name_uuid,
    135 		    uuid) == 0) {
    136 			return &toc_entry_lookup_list[lookup_index];
    137 		}
    138 		lookup_index++;
    139 	}
    140 	return NULL;
    141 }
    142 
    143 
    144 static file_info_t *find_file_info_from_uuid(const uuid_t *uuid)
    145 {
    146 	int index;
    147 
    148 	for (index = 0; index < file_info_count; index++) {
    149 		if (compare_uuids(&files[index].name_uuid, uuid) == 0) {
    150 			return &files[index];
    151 		}
    152 	}
    153 	return NULL;
    154 }
    155 
    156 
    157 static int add_file_info_entry(entry_lookup_list_t *lookup_entry, char *filename)
    158 {
    159 	file_info_t *file_info_entry;
    160 	int error;
    161 	struct stat file_status;
    162 	bool is_new_entry = false;
    163 
    164 	/* Check if the file already exists in the array */
    165 	file_info_entry = find_file_info_from_uuid(&lookup_entry->name_uuid);
    166 	if (file_info_entry == NULL) {
    167 		/* The file does not exist in the current list; take the next
    168 		 * one available in the file_info list. 'file_info_count' is
    169 		 * incremented in case of successful update at the end of the
    170 		 * function.
    171 		 */
    172 		file_info_entry = &files[file_info_count];
    173 		is_new_entry = true;
    174 
    175 		/* Copy the uuid for the new entry */
    176 		copy_uuid(&file_info_entry->name_uuid,
    177 			  &lookup_entry->name_uuid);
    178 	}
    179 
    180 	/* Get the file information for entry */
    181 	error = stat(filename, &file_status);
    182 	if (error != 0) {
    183 		printf("Error: Cannot get information for file \"%s\": %s\n",
    184 			filename, strerror(errno));
    185 		return errno;
    186 	}
    187 	file_info_entry->filename = filename;
    188 	file_info_entry->size = (unsigned int)file_status.st_size;
    189 	file_info_entry->entry = lookup_entry;
    190 
    191 	/* Increment the file_info counter on success if it is new file entry */
    192 	if (is_new_entry) {
    193 		file_info_count++;
    194 
    195 		/* Ensure we do not overflow */
    196 		if (file_info_count > MAX_FILES) {
    197 			printf("ERROR: Too many files in Package\n");
    198 			return 1;
    199 		}
    200 	}
    201 
    202 	return 0;
    203 }
    204 
    205 
    206 static int write_memory_to_file(const uint8_t *start, const char *filename,
    207 		unsigned int size)
    208 {
    209 	FILE *stream;
    210 	unsigned int bytes_written;
    211 
    212 	/* Write the packed file out to the filesystem */
    213 	stream = fopen(filename, "r+");
    214 	if (stream == NULL) {
    215 		stream = fopen(filename, "w");
    216 		if (stream == NULL) {
    217 			printf("Error: Cannot create output file \"%s\": %s\n",
    218 			       filename, strerror(errno));
    219 			return errno;
    220 		} else {
    221 			printf("Creating \"%s\"\n", filename);
    222 		}
    223 	} else {
    224 		printf("Updating \"%s\"\n", filename);
    225 	}
    226 
    227 	bytes_written = fwrite(start, sizeof(uint8_t), size, stream);
    228 	fclose(stream);
    229 
    230 	if (bytes_written != size) {
    231 		printf("Error: Incorrect write for file \"%s\": Size=%u,"
    232 			"Written=%u bytes.\n", filename, size, bytes_written);
    233 		return EIO;
    234 	}
    235 
    236 	return 0;
    237 }
    238 
    239 
    240 static int read_file_to_memory(void *memory, const file_info_t *info)
    241 {
    242 	FILE *stream;
    243 	unsigned int bytes_read;
    244 
    245 	/* If the file_info is defined by its filename we need to load it */
    246 	if (info->filename) {
    247 		/* Read image from filesystem */
    248 		stream = fopen(info->filename, "r");
    249 		if (stream == NULL) {
    250 			printf("Error: Cannot open file \"%s\": %s\n",
    251 				info->filename, strerror(errno));
    252 			return errno;
    253 		}
    254 
    255 		bytes_read = (unsigned int)fread(memory, sizeof(uint8_t),
    256 						 info->size, stream);
    257 		fclose(stream);
    258 		if (bytes_read != info->size) {
    259 			printf("Error: Incomplete read for file \"%s\":"
    260 				"Size=%u, Read=%u bytes.\n", info->filename,
    261 				info->size, bytes_read);
    262 			return EIO;
    263 		}
    264 	} else {
    265 		if (info->image_buffer == NULL) {
    266 			printf("ERROR: info->image_buffer = NULL\n");
    267 			return EIO;
    268 		}
    269 		/* Copy the file_info buffer (extracted from the existing
    270 		 * image package) into the new buffer.
    271 		 */
    272 		memcpy(memory, info->image_buffer, info->size);
    273 	}
    274 
    275 	return 0;
    276 }
    277 
    278 
    279 /* Create the image package file */
    280 static int pack_images(const char *fip_filename)
    281 {
    282 	int status;
    283 	uint8_t *fip_base_address;
    284 	void *entry_address;
    285 	fip_toc_header_t *toc_header;
    286 	fip_toc_entry_t *toc_entry;
    287 	unsigned int entry_index;
    288 	unsigned int toc_size;
    289 	unsigned int fip_size;
    290 	unsigned int entry_offset_address;
    291 	unsigned int payload_size = 0;
    292 
    293 	/* Validate filename */
    294 	if ((fip_filename == NULL) || (strcmp(fip_filename, "") == 0)) {
    295 		return EINVAL;
    296 	}
    297 
    298 	/* Payload size calculation */
    299 	for (entry_index = 0; entry_index < file_info_count; entry_index++) {
    300 		payload_size += files[entry_index].size;
    301 	}
    302 
    303 	/* Allocate memory for entire package, including the final null entry */
    304 	toc_size = (sizeof(fip_toc_header_t) +
    305 		    (sizeof(fip_toc_entry_t) * (file_info_count + 1)));
    306 	fip_size = toc_size + payload_size;
    307 	fip_base_address = malloc(fip_size);
    308 	if (fip_base_address == NULL) {
    309 		printf("Error: Can't allocate enough memory to create package."
    310 		       "Process aborted.\n");
    311 		return ENOMEM;
    312 	}
    313 	memset(fip_base_address, 0, fip_size);
    314 
    315 	/* Create ToC Header */
    316 	toc_header = (fip_toc_header_t *)fip_base_address;
    317 	toc_header->name = TOC_HEADER_NAME;
    318 	toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
    319 	toc_header->flags = 0;
    320 
    321 	toc_entry = (fip_toc_entry_t *)(fip_base_address +
    322 				      sizeof(fip_toc_header_t));
    323 
    324 	/* Calculate the starting address of the first image, right after the
    325 	 * toc header.
    326 	 */
    327 	entry_offset_address = toc_size;
    328 	entry_index = 0;
    329 
    330 	/* Create the package in memory. */
    331 	for (entry_index = 0; entry_index < file_info_count; entry_index++) {
    332 		entry_address = (fip_base_address + entry_offset_address);
    333 		status = read_file_to_memory(entry_address,
    334 					     &files[entry_index]);
    335 		if (status != 0) {
    336 			printf("Error: While reading \"%s\" from filesystem.\n",
    337 				files[entry_index].filename);
    338 			return status;
    339 		}
    340 
    341 		copy_uuid(&toc_entry->uuid, &files[entry_index].name_uuid);
    342 		toc_entry->offset_address = entry_offset_address;
    343 		toc_entry->size = files[entry_index].size;
    344 		toc_entry->flags = 0;
    345 		entry_offset_address += toc_entry->size;
    346 		toc_entry++;
    347 	}
    348 
    349 	/* Add a null uuid entry to mark the end of toc entries */
    350 	copy_uuid(&toc_entry->uuid, &uuid_null);
    351 	toc_entry->offset_address = entry_offset_address;
    352 	toc_entry->size = 0;
    353 	toc_entry->flags = 0;
    354 
    355 	/* Save the package to file */
    356 	status = write_memory_to_file(fip_base_address, fip_filename, fip_size);
    357 	if (status != 0) {
    358 		printf("Error: Failed while writing package to file \"%s\" "
    359 			"with status=%d.\n", fip_filename, status);
    360 		return status;
    361 	}
    362 	return 0;
    363 }
    364 
    365 
    366 static void dump_toc(void)
    367 {
    368 	unsigned int index = 0;
    369 	unsigned int image_offset;
    370 	unsigned int image_size = 0;
    371 
    372 	image_offset = sizeof(fip_toc_header_t) +
    373 		(sizeof(fip_toc_entry_t) * (file_info_count + 1));
    374 
    375 	printf("Firmware Image Package ToC:\n");
    376 	printf("---------------------------\n");
    377 	for (index = 0; index < file_info_count; index++) {
    378 		if (files[index].entry) {
    379 			printf("- %s: ", files[index].entry->name);
    380 		} else {
    381 			printf("- Unknown entry: ");
    382 		}
    383 		image_size = files[index].size;
    384 
    385 		printf("offset=0x%X, size=0x%X\n", image_offset, image_size);
    386 		image_offset += image_size;
    387 
    388 		if (files[index].filename) {
    389 			printf("  file: '%s'\n", files[index].filename);
    390 		}
    391 	}
    392 	printf("---------------------------\n");
    393 }
    394 
    395 
    396 /* Read and load existing package into memory. */
    397 static int parse_fip(const char *fip_filename)
    398 {
    399 	FILE *fip;
    400 	char *fip_buffer;
    401 	char *fip_buffer_end;
    402 	int fip_size, read_fip_size;
    403 	fip_toc_header_t *toc_header;
    404 	fip_toc_entry_t *toc_entry;
    405 	bool found_last_toc_entry = false;
    406 	file_info_t *file_info_entry;
    407 	int status = -1;
    408 	struct stat st;
    409 
    410 	fip = fopen(fip_filename, "r");
    411 	if (fip == NULL) {
    412 		/* If the fip does not exist just return, it should not be
    413 		 * considered as an error. The package will be created later
    414 		 */
    415 		status = 0;
    416 		goto parse_fip_return;
    417 	}
    418 
    419 	if (stat(fip_filename, &st) != 0) {
    420 		status = errno;
    421 		goto parse_fip_fclose;
    422 	} else {
    423 		fip_size = (int)st.st_size;
    424 	}
    425 
    426 	/* Allocate a buffer to read the package */
    427 	fip_buffer = (char *)malloc(fip_size);
    428 	if (fip_buffer == NULL) {
    429 		printf("ERROR: Cannot allocate %d bytes.\n", fip_size);
    430 		status = errno;
    431 		goto parse_fip_fclose;
    432 	}
    433 	fip_buffer_end = fip_buffer + fip_size;
    434 
    435 	/* Read the file */
    436 	read_fip_size = fread(fip_buffer, sizeof(char), fip_size, fip);
    437 	if (read_fip_size != fip_size) {
    438 		printf("ERROR: Cannot read the FIP.\n");
    439 		status = EIO;
    440 		goto parse_fip_free;
    441 	}
    442 	fclose(fip);
    443 	fip = NULL;
    444 
    445 	/* The package must at least contain the ToC Header */
    446 	if (fip_size < sizeof(fip_toc_header_t)) {
    447 		printf("ERROR: Given FIP is smaller than the ToC header.\n");
    448 		status = EINVAL;
    449 		goto parse_fip_free;
    450 	}
    451 	/* Set the ToC Header at the base of the buffer */
    452 	toc_header = (fip_toc_header_t *)fip_buffer;
    453 	/* The first toc entry should be just after the ToC header */
    454 	toc_entry = (fip_toc_entry_t *)(toc_header + 1);
    455 
    456 	/* While the ToC entry is contained into the buffer */
    457 	int cnt = 0;
    458 	while (((char *)toc_entry + sizeof(fip_toc_entry_t)) < fip_buffer_end) {
    459 		cnt++;
    460 		/* Check if the ToC Entry is the last one */
    461 		if (compare_uuids(&toc_entry->uuid, &uuid_null) == 0) {
    462 			found_last_toc_entry = true;
    463 			status = 0;
    464 			break;
    465 		}
    466 
    467 		/* Add the entry into file_info */
    468 
    469 		/* Get the new entry in the array and clear it */
    470 		file_info_entry = &files[file_info_count++];
    471 		memset(file_info_entry, 0, sizeof(file_info_t));
    472 
    473 		/* Copy the info from the ToC entry */
    474 		copy_uuid(&file_info_entry->name_uuid, &toc_entry->uuid);
    475 		file_info_entry->image_buffer = fip_buffer +
    476 		  toc_entry->offset_address;
    477 		file_info_entry->size = toc_entry->size;
    478 
    479 		/* Check if there is a corresponding entry in lookup table */
    480 		file_info_entry->entry =
    481 		  get_entry_lookup_from_uuid(&toc_entry->uuid);
    482 
    483 		/* Go to the next ToC entry */
    484 		toc_entry++;
    485 	}
    486 
    487 	if (!found_last_toc_entry) {
    488 		printf("ERROR: Given FIP does not have an end ToC entry.\n");
    489 		status = EINVAL;
    490 		goto parse_fip_free;
    491 	} else {
    492 		/* All is well, we should not free any of the loaded images */
    493 		goto parse_fip_fclose;
    494 	}
    495 
    496  parse_fip_free:
    497 	if (fip_buffer != NULL) {
    498 		free(fip_buffer);
    499 		fip_buffer = NULL;
    500 	}
    501 
    502  parse_fip_fclose:
    503 	if (fip != NULL) {
    504 		fclose(fip);
    505 	}
    506 
    507  parse_fip_return:
    508 	return status;
    509 }
    510 
    511 
    512 /* Parse all command-line options and return the FIP name if present. */
    513 static char *get_filename(int argc, char **argv, struct option *options)
    514 {
    515 	int c;
    516 	char *filename = NULL;
    517 
    518 	/* Reset option pointer so we parse all args. starts at 1.
    519 	 * The filename is the only argument that does not have an option flag.
    520 	 */
    521 	optind = 1;
    522 	while (1) {
    523 		c = getopt_long(argc, argv, "", options, NULL);
    524 		if (c == -1)
    525 			break;
    526 
    527 		if (c == '?') {
    528 			/* Failed to parse an option. Fail. */
    529 			return NULL;
    530 		}
    531 	}
    532 
    533 	/* Only one argument left then it is the filename.
    534 	 * We dont expect any other options
    535 	 */
    536 	if (optind + 1 == argc)
    537 		filename = argv[optind];
    538 
    539 	return filename;
    540 }
    541 
    542 
    543 /* Work through command-line options */
    544 static int parse_cmdline(int argc, char **argv, struct option *options,
    545 			 int *do_pack)
    546 {
    547 	int c;
    548 	int status = 0;
    549 	int option_index = 0;
    550 	entry_lookup_list_t *lookup_entry;
    551 	int do_dump = 0;
    552 
    553 	/* restart parse to process all options. starts at 1. */
    554 	optind = 1;
    555 	while (1) {
    556 		c = getopt_long(argc, argv, "", options, &option_index);
    557 		if (c == -1)
    558 			break;
    559 
    560 		switch (c) {
    561 		case OPT_TOC_ENTRY:
    562 			if (optarg) {
    563 				/* Does the option expect a filename. */
    564 				lookup_entry = &toc_entry_lookup_list[option_index];
    565 				if (lookup_entry->flags & FLAG_FILENAME) {
    566 					status = add_file_info_entry(lookup_entry, optarg);
    567 					if (status != 0) {
    568 						printf("Failed to process %s\n",
    569 						       options[option_index].name);
    570 						return status;
    571 					} else {
    572 						/* Update package */
    573 						*do_pack = 1;
    574 					}
    575 				}
    576 			}
    577 			break;
    578 
    579 		case OPT_DUMP:
    580 			do_dump = 1;
    581 			continue;
    582 
    583 		case OPT_HELP:
    584 			print_usage();
    585 			exit(0);
    586 
    587 		default:
    588 			/* Unrecognised options are caught in get_filename() */
    589 			break;
    590 		}
    591 	}
    592 
    593 
    594 	/* Do not dump toc if we have an error as it could hide the error */
    595 	if ((status == 0) && (do_dump)) {
    596 		dump_toc();
    597 	}
    598 
    599 	return status;
    600 
    601 }
    602 
    603 int main(int argc, char **argv)
    604 {
    605 	int i;
    606 	int status;
    607 	char *fip_filename;
    608 	int do_pack = 0;
    609 
    610 	/* Clear file list table. */
    611 	memset(files, 0, sizeof(files));
    612 
    613 	/* Initialise for getopt_long().
    614 	 * Use image table as defined at top of file to get options.
    615 	 * Add 'dump' option, 'help' option and end marker.
    616 	 */
    617 	static struct option long_options[(sizeof(toc_entry_lookup_list)/
    618 					   sizeof(entry_lookup_list_t)) + 2];
    619 
    620 	for (i = 0;
    621 	     /* -1 because we dont want to process end marker in toc table */
    622 	     i < sizeof(toc_entry_lookup_list)/sizeof(entry_lookup_list_t) - 1;
    623 	     i++) {
    624 		long_options[i].name = toc_entry_lookup_list[i].command_line_name;
    625 		/* The only flag defined at the moment is for a FILENAME */
    626 		long_options[i].has_arg = toc_entry_lookup_list[i].flags ? 1 : 0;
    627 		long_options[i].flag = 0;
    628 		long_options[i].val = OPT_TOC_ENTRY;
    629 	}
    630 
    631 	/* Add '--dump' option */
    632 	long_options[i].name = "dump";
    633 	long_options[i].has_arg = 0;
    634 	long_options[i].flag = 0;
    635 	long_options[i].val = OPT_DUMP;
    636 
    637 	/* Add '--help' option */
    638 	long_options[++i].name = "help";
    639 	long_options[i].has_arg = 0;
    640 	long_options[i].flag = 0;
    641 	long_options[i].val = OPT_HELP;
    642 
    643 	/* Zero the last entry (required) */
    644 	long_options[++i].name = 0;
    645 	long_options[i].has_arg = 0;
    646 	long_options[i].flag = 0;
    647 	long_options[i].val = 0;
    648 
    649 #ifdef DEBUG
    650 	/* Print all supported options */
    651 	for (i = 0; i < sizeof(long_options)/sizeof(struct option); i++) {
    652 		printf("long opt (%d) : name = %s\n", i, long_options[i].name);
    653 	}
    654 #endif /* DEBUG */
    655 
    656 	/* As the package may already exist and is to be updated we need to get
    657 	 * the filename from the arguments and load from it.
    658 	 * NOTE: As this is the first function to look at the program arguments
    659 	 * it causes a failure if bad options were provided.
    660 	 */
    661 	fip_filename = get_filename(argc, argv, long_options);
    662 
    663 	/* Try to open the file and load it into memory */
    664 	if (fip_filename != NULL) {
    665 		status = parse_fip(fip_filename);
    666 		if (status != 0) {
    667 			return status;
    668 		}
    669 	}
    670 
    671 	/* Work through provided program arguments and perform actions */
    672 	status = parse_cmdline(argc, argv, long_options, &do_pack);
    673 	if (status != 0) {
    674 		return status;
    675 	};
    676 
    677 	if (fip_filename == NULL) {
    678 		printf("ERROR: Missing FIP filename\n");
    679 		print_usage();
    680 		return 0;
    681 	}
    682 
    683 	/* Processed all command line options. Create/update the package if
    684 	 * required.
    685 	 */
    686 	if (do_pack) {
    687 		status = pack_images(fip_filename);
    688 		if (status != 0) {
    689 			printf("Failed to create package (status = %d).\n",
    690 			       status);
    691 		}
    692 	}
    693 
    694 	return status;
    695 }
    696