blob: 19afc7488e02d8930506aff55b09f3c9e5a4806d [file] [log] [blame]
Harry Liebelf58ad362014-01-10 18:00:33 +00001/*
Yatharth Kochar4dd39b82015-08-10 11:57:41 +01002 * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
Harry Liebelf58ad362014-01-10 18:00:33 +00003 *
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
Sandrine Bailleux29e54422014-03-19 13:09:54 +000041/* Values returned by getopt() as part of the command line parsing */
42#define OPT_TOC_ENTRY 0
43#define OPT_DUMP 1
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +000044#define OPT_HELP 2
Sandrine Bailleux29e54422014-03-19 13:09:54 +000045
Dan Handleye2712bc2014-04-10 15:37:22 +010046file_info_t files[MAX_FILES];
Harry Liebelf58ad362014-01-10 18:00:33 +000047unsigned file_info_count = 0;
48uuid_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
Harry Liebeleed7a5b2014-05-01 14:09:16 +010056/* The images used depends on the platform. */
Dan Handleye2712bc2014-04-10 15:37:22 +010057static entry_lookup_list_t toc_entry_lookup_list[] = {
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010058 { "SCP Firmware Updater Configuration FWU SCP_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U,
Juan Castillo8e04dec2016-01-05 11:55:36 +000059 "scp-fwu-cfg", NULL, FLAG_FILENAME },
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010060 { "AP Firmware Updater Configuration BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U,
Juan Castillo8e04dec2016-01-05 11:55:36 +000061 "ap-fwu-cfg", NULL, FLAG_FILENAME },
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010062 { "Firmware Updater NS_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U,
Juan Castillo8e04dec2016-01-05 11:55:36 +000063 "fwu", NULL, FLAG_FILENAME },
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010064 { "Non-Trusted Firmware Updater certificate", UUID_TRUSTED_FWU_CERT,
65 "fwu-cert", NULL, FLAG_FILENAME},
Harry Liebelf58ad362014-01-10 18:00:33 +000066 { "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2,
Juan Castillo8e04dec2016-01-05 11:55:36 +000067 "tb-fw", NULL, FLAG_FILENAME },
Juan Castilloa72b6472015-12-10 15:49:17 +000068 { "SCP Firmware SCP_BL2", UUID_SCP_FIRMWARE_SCP_BL2,
Juan Castillo8e04dec2016-01-05 11:55:36 +000069 "scp-fw", NULL, FLAG_FILENAME},
Juan Castillo7d199412015-12-14 09:35:25 +000070 { "EL3 Runtime Firmware BL31", UUID_EL3_RUNTIME_FIRMWARE_BL31,
Juan Castillo8e04dec2016-01-05 11:55:36 +000071 "soc-fw", NULL, FLAG_FILENAME},
Juan Castillo7d199412015-12-14 09:35:25 +000072 { "Secure Payload BL32 (Trusted OS)", UUID_SECURE_PAYLOAD_BL32,
Juan Castillo8e04dec2016-01-05 11:55:36 +000073 "tos-fw", NULL, FLAG_FILENAME},
Juan Castillo7d199412015-12-14 09:35:25 +000074 { "Non-Trusted Firmware BL33", UUID_NON_TRUSTED_FIRMWARE_BL33,
Juan Castillo8e04dec2016-01-05 11:55:36 +000075 "nt-fw", NULL, FLAG_FILENAME},
Juan Castillo379954c2014-11-04 17:36:40 +000076 /* Key Certificates */
77 { "Root Of Trust key certificate", UUID_ROT_KEY_CERT,
78 "rot-cert", NULL, FLAG_FILENAME },
79 { "Trusted key certificate", UUID_TRUSTED_KEY_CERT,
80 "trusted-key-cert", NULL, FLAG_FILENAME},
Juan Castillobe801202015-12-03 10:19:21 +000081 { "SCP Firmware key certificate", UUID_SCP_FW_KEY_CERT,
82 "scp-fw-key-cert", NULL, FLAG_FILENAME},
83 { "SoC Firmware key certificate", UUID_SOC_FW_KEY_CERT,
84 "soc-fw-key-cert", NULL, FLAG_FILENAME},
85 { "Trusted OS Firmware key certificate", UUID_TRUSTED_OS_FW_KEY_CERT,
86 "tos-fw-key-cert", NULL, FLAG_FILENAME},
87 { "Non-Trusted Firmware key certificate", UUID_NON_TRUSTED_FW_KEY_CERT,
88 "nt-fw-key-cert", NULL, FLAG_FILENAME},
Juan Castillo379954c2014-11-04 17:36:40 +000089 /* Content certificates */
Juan Castillobe801202015-12-03 10:19:21 +000090 { "Trusted Boot Firmware BL2 certificate", UUID_TRUSTED_BOOT_FW_CERT,
91 "tb-fw-cert", NULL, FLAG_FILENAME },
92 { "SCP Firmware content certificate", UUID_SCP_FW_CONTENT_CERT,
93 "scp-fw-cert", NULL, FLAG_FILENAME},
94 { "SoC Firmware content certificate", UUID_SOC_FW_CONTENT_CERT,
95 "soc-fw-cert", NULL, FLAG_FILENAME},
96 { "Trusted OS Firmware content certificate", UUID_TRUSTED_OS_FW_CONTENT_CERT,
97 "tos-fw-cert", NULL, FLAG_FILENAME},
98 { "Non-Trusted Firmware content certificate", UUID_NON_TRUSTED_FW_CONTENT_CERT,
99 "nt-fw-cert", NULL, FLAG_FILENAME},
Harry Liebelf58ad362014-01-10 18:00:33 +0000100 { NULL, {0}, 0 }
101};
102
103
104/* Return 0 for equal uuids */
105static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2)
106{
107 return memcmp(uuid1, uuid2, sizeof(uuid_t));
108}
109
110
111static inline void copy_uuid(uuid_t *to_uuid, const uuid_t *from_uuid)
112{
113 memcpy(to_uuid, from_uuid, sizeof(uuid_t));
114}
115
116
117static void print_usage(void)
118{
Dan Handleye2712bc2014-04-10 15:37:22 +0100119 entry_lookup_list_t *entry = toc_entry_lookup_list;
Harry Liebelf58ad362014-01-10 18:00:33 +0000120
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000121 printf("Usage: fip_create [options] FIP_FILENAME\n\n");
Harry Liebelf58ad362014-01-10 18:00:33 +0000122 printf("\tThis tool is used to create a Firmware Image Package.\n\n");
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000123 printf("Options:\n");
124 printf("\t--help: Print this help message and exit\n");
125 printf("\t--dump: Print contents of FIP\n\n");
Harry Liebelf58ad362014-01-10 18:00:33 +0000126 printf("\tComponents that can be added/updated:\n");
127 for (; entry->command_line_name != NULL; entry++) {
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000128 printf("\t--%s%s\t\t%s",
129 entry->command_line_name,
130 (entry->flags & FLAG_FILENAME) ? " FILENAME" : "",
131 entry->name);
132 printf("\n");
Harry Liebelf58ad362014-01-10 18:00:33 +0000133 }
134}
135
136
Dan Handleye2712bc2014-04-10 15:37:22 +0100137static entry_lookup_list_t *get_entry_lookup_from_uuid(const uuid_t *uuid)
Harry Liebelf58ad362014-01-10 18:00:33 +0000138{
139 unsigned int lookup_index = 0;
140
141 while (toc_entry_lookup_list[lookup_index].command_line_name != NULL) {
142 if (compare_uuids(&toc_entry_lookup_list[lookup_index].name_uuid,
143 uuid) == 0) {
144 return &toc_entry_lookup_list[lookup_index];
145 }
146 lookup_index++;
147 }
148 return NULL;
149}
150
151
Dan Handleye2712bc2014-04-10 15:37:22 +0100152static file_info_t *find_file_info_from_uuid(const uuid_t *uuid)
Harry Liebelf58ad362014-01-10 18:00:33 +0000153{
154 int index;
155
156 for (index = 0; index < file_info_count; index++) {
157 if (compare_uuids(&files[index].name_uuid, uuid) == 0) {
158 return &files[index];
159 }
160 }
161 return NULL;
162}
163
164
Dan Handleye2712bc2014-04-10 15:37:22 +0100165static int add_file_info_entry(entry_lookup_list_t *lookup_entry, char *filename)
Harry Liebelf58ad362014-01-10 18:00:33 +0000166{
Dan Handleye2712bc2014-04-10 15:37:22 +0100167 file_info_t *file_info_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000168 int error;
169 struct stat file_status;
170 bool is_new_entry = false;
171
172 /* Check if the file already exists in the array */
173 file_info_entry = find_file_info_from_uuid(&lookup_entry->name_uuid);
174 if (file_info_entry == NULL) {
175 /* The file does not exist in the current list; take the next
176 * one available in the file_info list. 'file_info_count' is
177 * incremented in case of successful update at the end of the
178 * function.
179 */
180 file_info_entry = &files[file_info_count];
181 is_new_entry = true;
182
183 /* Copy the uuid for the new entry */
184 copy_uuid(&file_info_entry->name_uuid,
185 &lookup_entry->name_uuid);
186 }
187
188 /* Get the file information for entry */
189 error = stat(filename, &file_status);
190 if (error != 0) {
191 printf("Error: Cannot get information for file \"%s\": %s\n",
192 filename, strerror(errno));
193 return errno;
194 }
195 file_info_entry->filename = filename;
196 file_info_entry->size = (unsigned int)file_status.st_size;
197 file_info_entry->entry = lookup_entry;
198
199 /* Increment the file_info counter on success if it is new file entry */
200 if (is_new_entry) {
201 file_info_count++;
202
203 /* Ensure we do not overflow */
204 if (file_info_count > MAX_FILES) {
205 printf("ERROR: Too many files in Package\n");
206 return 1;
207 }
208 }
209
210 return 0;
211}
212
213
214static int write_memory_to_file(const uint8_t *start, const char *filename,
215 unsigned int size)
216{
217 FILE *stream;
218 unsigned int bytes_written;
219
220 /* Write the packed file out to the filesystem */
221 stream = fopen(filename, "r+");
222 if (stream == NULL) {
223 stream = fopen(filename, "w");
224 if (stream == NULL) {
225 printf("Error: Cannot create output file \"%s\": %s\n",
226 filename, strerror(errno));
227 return errno;
228 } else {
229 printf("Creating \"%s\"\n", filename);
230 }
231 } else {
232 printf("Updating \"%s\"\n", filename);
233 }
234
235 bytes_written = fwrite(start, sizeof(uint8_t), size, stream);
236 fclose(stream);
237
238 if (bytes_written != size) {
239 printf("Error: Incorrect write for file \"%s\": Size=%u,"
240 "Written=%u bytes.\n", filename, size, bytes_written);
241 return EIO;
242 }
243
244 return 0;
245}
246
247
Dan Handleye2712bc2014-04-10 15:37:22 +0100248static int read_file_to_memory(void *memory, const file_info_t *info)
Harry Liebelf58ad362014-01-10 18:00:33 +0000249{
250 FILE *stream;
251 unsigned int bytes_read;
252
253 /* If the file_info is defined by its filename we need to load it */
254 if (info->filename) {
255 /* Read image from filesystem */
256 stream = fopen(info->filename, "r");
257 if (stream == NULL) {
258 printf("Error: Cannot open file \"%s\": %s\n",
259 info->filename, strerror(errno));
260 return errno;
261 }
262
263 bytes_read = (unsigned int)fread(memory, sizeof(uint8_t),
264 info->size, stream);
265 fclose(stream);
266 if (bytes_read != info->size) {
267 printf("Error: Incomplete read for file \"%s\":"
268 "Size=%u, Read=%u bytes.\n", info->filename,
269 info->size, bytes_read);
270 return EIO;
271 }
272 } else {
273 if (info->image_buffer == NULL) {
274 printf("ERROR: info->image_buffer = NULL\n");
275 return EIO;
276 }
277 /* Copy the file_info buffer (extracted from the existing
278 * image package) into the new buffer.
279 */
280 memcpy(memory, info->image_buffer, info->size);
281 }
282
283 return 0;
284}
285
286
287/* Create the image package file */
288static int pack_images(const char *fip_filename)
289{
290 int status;
291 uint8_t *fip_base_address;
292 void *entry_address;
Dan Handleye2712bc2014-04-10 15:37:22 +0100293 fip_toc_header_t *toc_header;
294 fip_toc_entry_t *toc_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000295 unsigned int entry_index;
296 unsigned int toc_size;
297 unsigned int fip_size;
298 unsigned int entry_offset_address;
299 unsigned int payload_size = 0;
300
301 /* Validate filename */
302 if ((fip_filename == NULL) || (strcmp(fip_filename, "") == 0)) {
303 return EINVAL;
304 }
305
306 /* Payload size calculation */
307 for (entry_index = 0; entry_index < file_info_count; entry_index++) {
308 payload_size += files[entry_index].size;
309 }
310
311 /* Allocate memory for entire package, including the final null entry */
Dan Handleye2712bc2014-04-10 15:37:22 +0100312 toc_size = (sizeof(fip_toc_header_t) +
313 (sizeof(fip_toc_entry_t) * (file_info_count + 1)));
Harry Liebelf58ad362014-01-10 18:00:33 +0000314 fip_size = toc_size + payload_size;
315 fip_base_address = malloc(fip_size);
316 if (fip_base_address == NULL) {
317 printf("Error: Can't allocate enough memory to create package."
318 "Process aborted.\n");
319 return ENOMEM;
320 }
321 memset(fip_base_address, 0, fip_size);
322
323 /* Create ToC Header */
Dan Handleye2712bc2014-04-10 15:37:22 +0100324 toc_header = (fip_toc_header_t *)fip_base_address;
Harry Liebelf58ad362014-01-10 18:00:33 +0000325 toc_header->name = TOC_HEADER_NAME;
326 toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
327 toc_header->flags = 0;
328
Dan Handleye2712bc2014-04-10 15:37:22 +0100329 toc_entry = (fip_toc_entry_t *)(fip_base_address +
330 sizeof(fip_toc_header_t));
Harry Liebelf58ad362014-01-10 18:00:33 +0000331
332 /* Calculate the starting address of the first image, right after the
333 * toc header.
334 */
335 entry_offset_address = toc_size;
336 entry_index = 0;
337
338 /* Create the package in memory. */
339 for (entry_index = 0; entry_index < file_info_count; entry_index++) {
340 entry_address = (fip_base_address + entry_offset_address);
341 status = read_file_to_memory(entry_address,
342 &files[entry_index]);
343 if (status != 0) {
344 printf("Error: While reading \"%s\" from filesystem.\n",
345 files[entry_index].filename);
346 return status;
347 }
348
349 copy_uuid(&toc_entry->uuid, &files[entry_index].name_uuid);
350 toc_entry->offset_address = entry_offset_address;
351 toc_entry->size = files[entry_index].size;
352 toc_entry->flags = 0;
353 entry_offset_address += toc_entry->size;
354 toc_entry++;
355 }
356
357 /* Add a null uuid entry to mark the end of toc entries */
358 copy_uuid(&toc_entry->uuid, &uuid_null);
359 toc_entry->offset_address = entry_offset_address;
360 toc_entry->size = 0;
361 toc_entry->flags = 0;
362
363 /* Save the package to file */
364 status = write_memory_to_file(fip_base_address, fip_filename, fip_size);
365 if (status != 0) {
366 printf("Error: Failed while writing package to file \"%s\" "
367 "with status=%d.\n", fip_filename, status);
368 return status;
369 }
370 return 0;
371}
372
373
374static void dump_toc(void)
375{
376 unsigned int index = 0;
377 unsigned int image_offset;
378 unsigned int image_size = 0;
379
Dan Handleye2712bc2014-04-10 15:37:22 +0100380 image_offset = sizeof(fip_toc_header_t) +
381 (sizeof(fip_toc_entry_t) * (file_info_count + 1));
Harry Liebelf58ad362014-01-10 18:00:33 +0000382
383 printf("Firmware Image Package ToC:\n");
384 printf("---------------------------\n");
385 for (index = 0; index < file_info_count; index++) {
386 if (files[index].entry) {
387 printf("- %s: ", files[index].entry->name);
388 } else {
389 printf("- Unknown entry: ");
390 }
391 image_size = files[index].size;
392
393 printf("offset=0x%X, size=0x%X\n", image_offset, image_size);
394 image_offset += image_size;
395
396 if (files[index].filename) {
397 printf(" file: '%s'\n", files[index].filename);
398 }
399 }
400 printf("---------------------------\n");
401}
402
403
404/* Read and load existing package into memory. */
405static int parse_fip(const char *fip_filename)
406{
407 FILE *fip;
408 char *fip_buffer;
409 char *fip_buffer_end;
410 int fip_size, read_fip_size;
Dan Handleye2712bc2014-04-10 15:37:22 +0100411 fip_toc_header_t *toc_header;
412 fip_toc_entry_t *toc_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000413 bool found_last_toc_entry = false;
Dan Handleye2712bc2014-04-10 15:37:22 +0100414 file_info_t *file_info_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000415 int status = -1;
416 struct stat st;
417
418 fip = fopen(fip_filename, "r");
419 if (fip == NULL) {
420 /* If the fip does not exist just return, it should not be
421 * considered as an error. The package will be created later
422 */
423 status = 0;
424 goto parse_fip_return;
425 }
426
427 if (stat(fip_filename, &st) != 0) {
428 status = errno;
429 goto parse_fip_fclose;
430 } else {
431 fip_size = (int)st.st_size;
432 }
433
434 /* Allocate a buffer to read the package */
435 fip_buffer = (char *)malloc(fip_size);
436 if (fip_buffer == NULL) {
437 printf("ERROR: Cannot allocate %d bytes.\n", fip_size);
438 status = errno;
439 goto parse_fip_fclose;
440 }
441 fip_buffer_end = fip_buffer + fip_size;
442
443 /* Read the file */
444 read_fip_size = fread(fip_buffer, sizeof(char), fip_size, fip);
445 if (read_fip_size != fip_size) {
446 printf("ERROR: Cannot read the FIP.\n");
447 status = EIO;
448 goto parse_fip_free;
449 }
450 fclose(fip);
451 fip = NULL;
452
453 /* The package must at least contain the ToC Header */
Dan Handleye2712bc2014-04-10 15:37:22 +0100454 if (fip_size < sizeof(fip_toc_header_t)) {
Harry Liebelf58ad362014-01-10 18:00:33 +0000455 printf("ERROR: Given FIP is smaller than the ToC header.\n");
456 status = EINVAL;
457 goto parse_fip_free;
458 }
459 /* Set the ToC Header at the base of the buffer */
Dan Handleye2712bc2014-04-10 15:37:22 +0100460 toc_header = (fip_toc_header_t *)fip_buffer;
Harry Liebelf58ad362014-01-10 18:00:33 +0000461 /* The first toc entry should be just after the ToC header */
Dan Handleye2712bc2014-04-10 15:37:22 +0100462 toc_entry = (fip_toc_entry_t *)(toc_header + 1);
Harry Liebelf58ad362014-01-10 18:00:33 +0000463
464 /* While the ToC entry is contained into the buffer */
465 int cnt = 0;
Dan Handleye2712bc2014-04-10 15:37:22 +0100466 while (((char *)toc_entry + sizeof(fip_toc_entry_t)) < fip_buffer_end) {
Harry Liebelf58ad362014-01-10 18:00:33 +0000467 cnt++;
468 /* Check if the ToC Entry is the last one */
469 if (compare_uuids(&toc_entry->uuid, &uuid_null) == 0) {
470 found_last_toc_entry = true;
471 status = 0;
472 break;
473 }
474
475 /* Add the entry into file_info */
476
477 /* Get the new entry in the array and clear it */
478 file_info_entry = &files[file_info_count++];
Dan Handleye2712bc2014-04-10 15:37:22 +0100479 memset(file_info_entry, 0, sizeof(file_info_t));
Harry Liebelf58ad362014-01-10 18:00:33 +0000480
481 /* Copy the info from the ToC entry */
482 copy_uuid(&file_info_entry->name_uuid, &toc_entry->uuid);
483 file_info_entry->image_buffer = fip_buffer +
484 toc_entry->offset_address;
485 file_info_entry->size = toc_entry->size;
486
487 /* Check if there is a corresponding entry in lookup table */
488 file_info_entry->entry =
489 get_entry_lookup_from_uuid(&toc_entry->uuid);
490
491 /* Go to the next ToC entry */
492 toc_entry++;
493 }
494
495 if (!found_last_toc_entry) {
496 printf("ERROR: Given FIP does not have an end ToC entry.\n");
497 status = EINVAL;
498 goto parse_fip_free;
499 } else {
500 /* All is well, we should not free any of the loaded images */
501 goto parse_fip_fclose;
502 }
503
504 parse_fip_free:
505 if (fip_buffer != NULL) {
506 free(fip_buffer);
507 fip_buffer = NULL;
508 }
509
510 parse_fip_fclose:
511 if (fip != NULL) {
512 fclose(fip);
513 }
514
515 parse_fip_return:
516 return status;
517}
518
519
520/* Parse all command-line options and return the FIP name if present. */
521static char *get_filename(int argc, char **argv, struct option *options)
522{
523 int c;
524 char *filename = NULL;
525
526 /* Reset option pointer so we parse all args. starts at 1.
527 * The filename is the only argument that does not have an option flag.
528 */
529 optind = 1;
530 while (1) {
531 c = getopt_long(argc, argv, "", options, NULL);
532 if (c == -1)
533 break;
534
535 if (c == '?') {
536 /* Failed to parse an option. Fail. */
537 return NULL;
538 }
539 }
540
541 /* Only one argument left then it is the filename.
542 * We dont expect any other options
543 */
Sandrine Bailleuxfce7a7d2014-03-19 13:39:52 +0000544 if (optind + 1 == argc)
Harry Liebelf58ad362014-01-10 18:00:33 +0000545 filename = argv[optind];
Harry Liebelf58ad362014-01-10 18:00:33 +0000546
547 return filename;
548}
549
550
551/* Work through command-line options */
552static int parse_cmdline(int argc, char **argv, struct option *options,
553 int *do_pack)
554{
555 int c;
556 int status = 0;
557 int option_index = 0;
Dan Handleye2712bc2014-04-10 15:37:22 +0100558 entry_lookup_list_t *lookup_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000559 int do_dump = 0;
560
561 /* restart parse to process all options. starts at 1. */
562 optind = 1;
563 while (1) {
564 c = getopt_long(argc, argv, "", options, &option_index);
565 if (c == -1)
566 break;
567
568 switch (c) {
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000569 case OPT_TOC_ENTRY:
Harry Liebelf58ad362014-01-10 18:00:33 +0000570 if (optarg) {
571 /* Does the option expect a filename. */
572 lookup_entry = &toc_entry_lookup_list[option_index];
573 if (lookup_entry->flags & FLAG_FILENAME) {
574 status = add_file_info_entry(lookup_entry, optarg);
575 if (status != 0) {
576 printf("Failed to process %s\n",
577 options[option_index].name);
Kévin Petit90983a52014-12-08 13:23:09 +0000578 return status;
Harry Liebelf58ad362014-01-10 18:00:33 +0000579 } else {
580 /* Update package */
581 *do_pack = 1;
582 }
583 }
584 }
585 break;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000586
587 case OPT_DUMP:
588 do_dump = 1;
589 continue;
590
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000591 case OPT_HELP:
592 print_usage();
593 exit(0);
594
Harry Liebelf58ad362014-01-10 18:00:33 +0000595 default:
596 /* Unrecognised options are caught in get_filename() */
597 break;
598 }
599 }
600
601
602 /* Do not dump toc if we have an error as it could hide the error */
603 if ((status == 0) && (do_dump)) {
604 dump_toc();
605 }
606
607 return status;
608
609}
610
611int main(int argc, char **argv)
612{
613 int i;
614 int status;
615 char *fip_filename;
616 int do_pack = 0;
617
618 /* Clear file list table. */
619 memset(files, 0, sizeof(files));
620
621 /* Initialise for getopt_long().
622 * Use image table as defined at top of file to get options.
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000623 * Add 'dump' option, 'help' option and end marker.
Harry Liebelf58ad362014-01-10 18:00:33 +0000624 */
625 static struct option long_options[(sizeof(toc_entry_lookup_list)/
Dan Handleye2712bc2014-04-10 15:37:22 +0100626 sizeof(entry_lookup_list_t)) + 2];
Harry Liebelf58ad362014-01-10 18:00:33 +0000627
628 for (i = 0;
629 /* -1 because we dont want to process end marker in toc table */
Dan Handleye2712bc2014-04-10 15:37:22 +0100630 i < sizeof(toc_entry_lookup_list)/sizeof(entry_lookup_list_t) - 1;
Harry Liebelf58ad362014-01-10 18:00:33 +0000631 i++) {
632 long_options[i].name = toc_entry_lookup_list[i].command_line_name;
633 /* The only flag defined at the moment is for a FILENAME */
634 long_options[i].has_arg = toc_entry_lookup_list[i].flags ? 1 : 0;
635 long_options[i].flag = 0;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000636 long_options[i].val = OPT_TOC_ENTRY;
Harry Liebelf58ad362014-01-10 18:00:33 +0000637 }
638
639 /* Add '--dump' option */
640 long_options[i].name = "dump";
641 long_options[i].has_arg = 0;
642 long_options[i].flag = 0;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000643 long_options[i].val = OPT_DUMP;
Harry Liebelf58ad362014-01-10 18:00:33 +0000644
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000645 /* Add '--help' option */
646 long_options[++i].name = "help";
647 long_options[i].has_arg = 0;
648 long_options[i].flag = 0;
649 long_options[i].val = OPT_HELP;
650
Harry Liebelf58ad362014-01-10 18:00:33 +0000651 /* Zero the last entry (required) */
652 long_options[++i].name = 0;
653 long_options[i].has_arg = 0;
654 long_options[i].flag = 0;
655 long_options[i].val = 0;
656
657#ifdef DEBUG
658 /* Print all supported options */
659 for (i = 0; i < sizeof(long_options)/sizeof(struct option); i++) {
660 printf("long opt (%d) : name = %s\n", i, long_options[i].name);
661 }
662#endif /* DEBUG */
663
664 /* As the package may already exist and is to be updated we need to get
665 * the filename from the arguments and load from it.
666 * NOTE: As this is the first function to look at the program arguments
667 * it causes a failure if bad options were provided.
668 */
669 fip_filename = get_filename(argc, argv, long_options);
Harry Liebelf58ad362014-01-10 18:00:33 +0000670
671 /* Try to open the file and load it into memory */
Sandrine Bailleuxfce7a7d2014-03-19 13:39:52 +0000672 if (fip_filename != NULL) {
673 status = parse_fip(fip_filename);
674 if (status != 0) {
675 return status;
676 }
Harry Liebelf58ad362014-01-10 18:00:33 +0000677 }
678
679 /* Work through provided program arguments and perform actions */
680 status = parse_cmdline(argc, argv, long_options, &do_pack);
681 if (status != 0) {
682 return status;
683 };
684
Sandrine Bailleuxfce7a7d2014-03-19 13:39:52 +0000685 if (fip_filename == NULL) {
686 printf("ERROR: Missing FIP filename\n");
687 print_usage();
688 return 0;
689 }
690
Harry Liebelf58ad362014-01-10 18:00:33 +0000691 /* Processed all command line options. Create/update the package if
692 * required.
693 */
694 if (do_pack) {
695 status = pack_images(fip_filename);
696 if (status != 0) {
697 printf("Failed to create package (status = %d).\n",
698 status);
699 }
700 }
701
702 return status;
703}