blob: dab9eb6db4173e7de05514207b494f0ce5acbbe3 [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
Juan Castillo314a6082016-02-15 17:21:10 +000043#define OPT_DUMP 'd'
44#define OPT_HELP 'h'
45#define OPT_STR "dh"
Sandrine Bailleux29e54422014-03-19 13:09:54 +000046
Juan Castillo314a6082016-02-15 17:21:10 +000047static file_info_t files[MAX_FILES];
48static unsigned file_info_count;
49static uuid_t uuid_null = {0};
50static int do_dump;
51static int do_pack;
Harry Liebelf58ad362014-01-10 18:00:33 +000052
53/*
54 * TODO: Add ability to specify and flag different file types.
55 * Add flags to the toc_entry?
56 * const char* format_type_str[] = { "RAW", "ELF", "PIC" };
57 */
58
Harry Liebeleed7a5b2014-05-01 14:09:16 +010059/* The images used depends on the platform. */
Dan Handleye2712bc2014-04-10 15:37:22 +010060static entry_lookup_list_t toc_entry_lookup_list[] = {
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010061 { "SCP Firmware Updater Configuration FWU SCP_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U,
Juan Castillo8e04dec2016-01-05 11:55:36 +000062 "scp-fwu-cfg", NULL, FLAG_FILENAME },
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010063 { "AP Firmware Updater Configuration BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U,
Juan Castillo8e04dec2016-01-05 11:55:36 +000064 "ap-fwu-cfg", NULL, FLAG_FILENAME },
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010065 { "Firmware Updater NS_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U,
Juan Castillo8e04dec2016-01-05 11:55:36 +000066 "fwu", NULL, FLAG_FILENAME },
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010067 { "Non-Trusted Firmware Updater certificate", UUID_TRUSTED_FWU_CERT,
68 "fwu-cert", NULL, FLAG_FILENAME},
Harry Liebelf58ad362014-01-10 18:00:33 +000069 { "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2,
Juan Castillo8e04dec2016-01-05 11:55:36 +000070 "tb-fw", NULL, FLAG_FILENAME },
Juan Castilloa72b6472015-12-10 15:49:17 +000071 { "SCP Firmware SCP_BL2", UUID_SCP_FIRMWARE_SCP_BL2,
Juan Castillo8e04dec2016-01-05 11:55:36 +000072 "scp-fw", NULL, FLAG_FILENAME},
Juan Castillo7d199412015-12-14 09:35:25 +000073 { "EL3 Runtime Firmware BL31", UUID_EL3_RUNTIME_FIRMWARE_BL31,
Juan Castillo8e04dec2016-01-05 11:55:36 +000074 "soc-fw", NULL, FLAG_FILENAME},
Juan Castillo7d199412015-12-14 09:35:25 +000075 { "Secure Payload BL32 (Trusted OS)", UUID_SECURE_PAYLOAD_BL32,
Juan Castillo8e04dec2016-01-05 11:55:36 +000076 "tos-fw", NULL, FLAG_FILENAME},
Juan Castillo7d199412015-12-14 09:35:25 +000077 { "Non-Trusted Firmware BL33", UUID_NON_TRUSTED_FIRMWARE_BL33,
Juan Castillo8e04dec2016-01-05 11:55:36 +000078 "nt-fw", NULL, FLAG_FILENAME},
Juan Castillo379954c2014-11-04 17:36:40 +000079 /* Key Certificates */
80 { "Root Of Trust key certificate", UUID_ROT_KEY_CERT,
81 "rot-cert", NULL, FLAG_FILENAME },
82 { "Trusted key certificate", UUID_TRUSTED_KEY_CERT,
83 "trusted-key-cert", NULL, FLAG_FILENAME},
Juan Castillobe801202015-12-03 10:19:21 +000084 { "SCP Firmware key certificate", UUID_SCP_FW_KEY_CERT,
85 "scp-fw-key-cert", NULL, FLAG_FILENAME},
86 { "SoC Firmware key certificate", UUID_SOC_FW_KEY_CERT,
87 "soc-fw-key-cert", NULL, FLAG_FILENAME},
88 { "Trusted OS Firmware key certificate", UUID_TRUSTED_OS_FW_KEY_CERT,
89 "tos-fw-key-cert", NULL, FLAG_FILENAME},
90 { "Non-Trusted Firmware key certificate", UUID_NON_TRUSTED_FW_KEY_CERT,
91 "nt-fw-key-cert", NULL, FLAG_FILENAME},
Juan Castillo379954c2014-11-04 17:36:40 +000092 /* Content certificates */
Juan Castillobe801202015-12-03 10:19:21 +000093 { "Trusted Boot Firmware BL2 certificate", UUID_TRUSTED_BOOT_FW_CERT,
94 "tb-fw-cert", NULL, FLAG_FILENAME },
95 { "SCP Firmware content certificate", UUID_SCP_FW_CONTENT_CERT,
96 "scp-fw-cert", NULL, FLAG_FILENAME},
97 { "SoC Firmware content certificate", UUID_SOC_FW_CONTENT_CERT,
98 "soc-fw-cert", NULL, FLAG_FILENAME},
99 { "Trusted OS Firmware content certificate", UUID_TRUSTED_OS_FW_CONTENT_CERT,
100 "tos-fw-cert", NULL, FLAG_FILENAME},
101 { "Non-Trusted Firmware content certificate", UUID_NON_TRUSTED_FW_CONTENT_CERT,
102 "nt-fw-cert", NULL, FLAG_FILENAME},
Harry Liebelf58ad362014-01-10 18:00:33 +0000103 { NULL, {0}, 0 }
104};
105
106
107/* Return 0 for equal uuids */
108static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2)
109{
110 return memcmp(uuid1, uuid2, sizeof(uuid_t));
111}
112
113
114static inline void copy_uuid(uuid_t *to_uuid, const uuid_t *from_uuid)
115{
116 memcpy(to_uuid, from_uuid, sizeof(uuid_t));
117}
118
119
120static void print_usage(void)
121{
Dan Handleye2712bc2014-04-10 15:37:22 +0100122 entry_lookup_list_t *entry = toc_entry_lookup_list;
Harry Liebelf58ad362014-01-10 18:00:33 +0000123
Juan Castillo314a6082016-02-15 17:21:10 +0000124 printf("\nThis tool is used to create a Firmware Image Package.\n\n");
125 printf("Usage:\n");
126 printf("\tfip_create [options] FIP_FILENAME\n\n");
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000127 printf("Options:\n");
Juan Castillo314a6082016-02-15 17:21:10 +0000128 printf("\t-h,--help: Print this help message and exit\n");
129 printf("\t-d,--dump: Print contents of FIP after update\n");
130 printf("Components that can be added/updated:\n");
Harry Liebelf58ad362014-01-10 18:00:33 +0000131 for (; entry->command_line_name != NULL; entry++) {
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000132 printf("\t--%s%s\t\t%s",
133 entry->command_line_name,
134 (entry->flags & FLAG_FILENAME) ? " FILENAME" : "",
135 entry->name);
136 printf("\n");
Harry Liebelf58ad362014-01-10 18:00:33 +0000137 }
Juan Castillo314a6082016-02-15 17:21:10 +0000138 printf("\n");
Harry Liebelf58ad362014-01-10 18:00:33 +0000139}
140
141
Dan Handleye2712bc2014-04-10 15:37:22 +0100142static entry_lookup_list_t *get_entry_lookup_from_uuid(const uuid_t *uuid)
Harry Liebelf58ad362014-01-10 18:00:33 +0000143{
144 unsigned int lookup_index = 0;
145
146 while (toc_entry_lookup_list[lookup_index].command_line_name != NULL) {
147 if (compare_uuids(&toc_entry_lookup_list[lookup_index].name_uuid,
148 uuid) == 0) {
149 return &toc_entry_lookup_list[lookup_index];
150 }
151 lookup_index++;
152 }
153 return NULL;
154}
155
156
Dan Handleye2712bc2014-04-10 15:37:22 +0100157static file_info_t *find_file_info_from_uuid(const uuid_t *uuid)
Harry Liebelf58ad362014-01-10 18:00:33 +0000158{
159 int index;
160
161 for (index = 0; index < file_info_count; index++) {
162 if (compare_uuids(&files[index].name_uuid, uuid) == 0) {
163 return &files[index];
164 }
165 }
166 return NULL;
167}
168
169
Dan Handleye2712bc2014-04-10 15:37:22 +0100170static int add_file_info_entry(entry_lookup_list_t *lookup_entry, char *filename)
Harry Liebelf58ad362014-01-10 18:00:33 +0000171{
Dan Handleye2712bc2014-04-10 15:37:22 +0100172 file_info_t *file_info_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000173 int error;
174 struct stat file_status;
175 bool is_new_entry = false;
176
177 /* Check if the file already exists in the array */
178 file_info_entry = find_file_info_from_uuid(&lookup_entry->name_uuid);
179 if (file_info_entry == NULL) {
180 /* The file does not exist in the current list; take the next
181 * one available in the file_info list. 'file_info_count' is
182 * incremented in case of successful update at the end of the
183 * function.
184 */
185 file_info_entry = &files[file_info_count];
186 is_new_entry = true;
187
188 /* Copy the uuid for the new entry */
189 copy_uuid(&file_info_entry->name_uuid,
190 &lookup_entry->name_uuid);
191 }
192
193 /* Get the file information for entry */
194 error = stat(filename, &file_status);
195 if (error != 0) {
196 printf("Error: Cannot get information for file \"%s\": %s\n",
197 filename, strerror(errno));
198 return errno;
199 }
200 file_info_entry->filename = filename;
201 file_info_entry->size = (unsigned int)file_status.st_size;
202 file_info_entry->entry = lookup_entry;
203
204 /* Increment the file_info counter on success if it is new file entry */
205 if (is_new_entry) {
206 file_info_count++;
207
208 /* Ensure we do not overflow */
209 if (file_info_count > MAX_FILES) {
210 printf("ERROR: Too many files in Package\n");
211 return 1;
212 }
213 }
214
215 return 0;
216}
217
218
219static int write_memory_to_file(const uint8_t *start, const char *filename,
220 unsigned int size)
221{
222 FILE *stream;
223 unsigned int bytes_written;
224
225 /* Write the packed file out to the filesystem */
226 stream = fopen(filename, "r+");
227 if (stream == NULL) {
228 stream = fopen(filename, "w");
229 if (stream == NULL) {
230 printf("Error: Cannot create output file \"%s\": %s\n",
231 filename, strerror(errno));
232 return errno;
233 } else {
234 printf("Creating \"%s\"\n", filename);
235 }
236 } else {
237 printf("Updating \"%s\"\n", filename);
238 }
239
240 bytes_written = fwrite(start, sizeof(uint8_t), size, stream);
241 fclose(stream);
242
243 if (bytes_written != size) {
244 printf("Error: Incorrect write for file \"%s\": Size=%u,"
245 "Written=%u bytes.\n", filename, size, bytes_written);
246 return EIO;
247 }
248
249 return 0;
250}
251
252
Dan Handleye2712bc2014-04-10 15:37:22 +0100253static int read_file_to_memory(void *memory, const file_info_t *info)
Harry Liebelf58ad362014-01-10 18:00:33 +0000254{
255 FILE *stream;
256 unsigned int bytes_read;
257
258 /* If the file_info is defined by its filename we need to load it */
259 if (info->filename) {
260 /* Read image from filesystem */
261 stream = fopen(info->filename, "r");
262 if (stream == NULL) {
263 printf("Error: Cannot open file \"%s\": %s\n",
264 info->filename, strerror(errno));
265 return errno;
266 }
267
268 bytes_read = (unsigned int)fread(memory, sizeof(uint8_t),
269 info->size, stream);
270 fclose(stream);
271 if (bytes_read != info->size) {
272 printf("Error: Incomplete read for file \"%s\":"
273 "Size=%u, Read=%u bytes.\n", info->filename,
274 info->size, bytes_read);
275 return EIO;
276 }
277 } else {
278 if (info->image_buffer == NULL) {
279 printf("ERROR: info->image_buffer = NULL\n");
280 return EIO;
281 }
282 /* Copy the file_info buffer (extracted from the existing
283 * image package) into the new buffer.
284 */
285 memcpy(memory, info->image_buffer, info->size);
286 }
287
288 return 0;
289}
290
291
292/* Create the image package file */
293static int pack_images(const char *fip_filename)
294{
295 int status;
296 uint8_t *fip_base_address;
297 void *entry_address;
Dan Handleye2712bc2014-04-10 15:37:22 +0100298 fip_toc_header_t *toc_header;
299 fip_toc_entry_t *toc_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000300 unsigned int entry_index;
301 unsigned int toc_size;
302 unsigned int fip_size;
303 unsigned int entry_offset_address;
304 unsigned int payload_size = 0;
305
306 /* Validate filename */
307 if ((fip_filename == NULL) || (strcmp(fip_filename, "") == 0)) {
308 return EINVAL;
309 }
310
311 /* Payload size calculation */
312 for (entry_index = 0; entry_index < file_info_count; entry_index++) {
313 payload_size += files[entry_index].size;
314 }
315
316 /* Allocate memory for entire package, including the final null entry */
Dan Handleye2712bc2014-04-10 15:37:22 +0100317 toc_size = (sizeof(fip_toc_header_t) +
318 (sizeof(fip_toc_entry_t) * (file_info_count + 1)));
Harry Liebelf58ad362014-01-10 18:00:33 +0000319 fip_size = toc_size + payload_size;
320 fip_base_address = malloc(fip_size);
321 if (fip_base_address == NULL) {
322 printf("Error: Can't allocate enough memory to create package."
323 "Process aborted.\n");
324 return ENOMEM;
325 }
326 memset(fip_base_address, 0, fip_size);
327
328 /* Create ToC Header */
Dan Handleye2712bc2014-04-10 15:37:22 +0100329 toc_header = (fip_toc_header_t *)fip_base_address;
Harry Liebelf58ad362014-01-10 18:00:33 +0000330 toc_header->name = TOC_HEADER_NAME;
331 toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
332 toc_header->flags = 0;
333
Dan Handleye2712bc2014-04-10 15:37:22 +0100334 toc_entry = (fip_toc_entry_t *)(fip_base_address +
335 sizeof(fip_toc_header_t));
Harry Liebelf58ad362014-01-10 18:00:33 +0000336
337 /* Calculate the starting address of the first image, right after the
338 * toc header.
339 */
340 entry_offset_address = toc_size;
341 entry_index = 0;
342
343 /* Create the package in memory. */
344 for (entry_index = 0; entry_index < file_info_count; entry_index++) {
345 entry_address = (fip_base_address + entry_offset_address);
346 status = read_file_to_memory(entry_address,
347 &files[entry_index]);
348 if (status != 0) {
349 printf("Error: While reading \"%s\" from filesystem.\n",
350 files[entry_index].filename);
351 return status;
352 }
353
354 copy_uuid(&toc_entry->uuid, &files[entry_index].name_uuid);
355 toc_entry->offset_address = entry_offset_address;
356 toc_entry->size = files[entry_index].size;
357 toc_entry->flags = 0;
358 entry_offset_address += toc_entry->size;
359 toc_entry++;
360 }
361
362 /* Add a null uuid entry to mark the end of toc entries */
363 copy_uuid(&toc_entry->uuid, &uuid_null);
364 toc_entry->offset_address = entry_offset_address;
365 toc_entry->size = 0;
366 toc_entry->flags = 0;
367
368 /* Save the package to file */
369 status = write_memory_to_file(fip_base_address, fip_filename, fip_size);
370 if (status != 0) {
371 printf("Error: Failed while writing package to file \"%s\" "
372 "with status=%d.\n", fip_filename, status);
373 return status;
374 }
375 return 0;
376}
377
378
379static void dump_toc(void)
380{
381 unsigned int index = 0;
382 unsigned int image_offset;
383 unsigned int image_size = 0;
384
Dan Handleye2712bc2014-04-10 15:37:22 +0100385 image_offset = sizeof(fip_toc_header_t) +
386 (sizeof(fip_toc_entry_t) * (file_info_count + 1));
Harry Liebelf58ad362014-01-10 18:00:33 +0000387
388 printf("Firmware Image Package ToC:\n");
389 printf("---------------------------\n");
390 for (index = 0; index < file_info_count; index++) {
391 if (files[index].entry) {
392 printf("- %s: ", files[index].entry->name);
393 } else {
394 printf("- Unknown entry: ");
395 }
396 image_size = files[index].size;
397
398 printf("offset=0x%X, size=0x%X\n", image_offset, image_size);
399 image_offset += image_size;
400
401 if (files[index].filename) {
402 printf(" file: '%s'\n", files[index].filename);
403 }
404 }
405 printf("---------------------------\n");
406}
407
408
409/* Read and load existing package into memory. */
410static int parse_fip(const char *fip_filename)
411{
412 FILE *fip;
413 char *fip_buffer;
414 char *fip_buffer_end;
415 int fip_size, read_fip_size;
Dan Handleye2712bc2014-04-10 15:37:22 +0100416 fip_toc_header_t *toc_header;
417 fip_toc_entry_t *toc_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000418 bool found_last_toc_entry = false;
Dan Handleye2712bc2014-04-10 15:37:22 +0100419 file_info_t *file_info_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000420 int status = -1;
421 struct stat st;
422
423 fip = fopen(fip_filename, "r");
424 if (fip == NULL) {
425 /* If the fip does not exist just return, it should not be
426 * considered as an error. The package will be created later
427 */
428 status = 0;
429 goto parse_fip_return;
430 }
431
432 if (stat(fip_filename, &st) != 0) {
433 status = errno;
434 goto parse_fip_fclose;
435 } else {
436 fip_size = (int)st.st_size;
437 }
438
439 /* Allocate a buffer to read the package */
440 fip_buffer = (char *)malloc(fip_size);
441 if (fip_buffer == NULL) {
442 printf("ERROR: Cannot allocate %d bytes.\n", fip_size);
443 status = errno;
444 goto parse_fip_fclose;
445 }
446 fip_buffer_end = fip_buffer + fip_size;
447
448 /* Read the file */
449 read_fip_size = fread(fip_buffer, sizeof(char), fip_size, fip);
450 if (read_fip_size != fip_size) {
451 printf("ERROR: Cannot read the FIP.\n");
452 status = EIO;
453 goto parse_fip_free;
454 }
455 fclose(fip);
456 fip = NULL;
457
458 /* The package must at least contain the ToC Header */
Dan Handleye2712bc2014-04-10 15:37:22 +0100459 if (fip_size < sizeof(fip_toc_header_t)) {
Harry Liebelf58ad362014-01-10 18:00:33 +0000460 printf("ERROR: Given FIP is smaller than the ToC header.\n");
461 status = EINVAL;
462 goto parse_fip_free;
463 }
464 /* Set the ToC Header at the base of the buffer */
Dan Handleye2712bc2014-04-10 15:37:22 +0100465 toc_header = (fip_toc_header_t *)fip_buffer;
Harry Liebelf58ad362014-01-10 18:00:33 +0000466 /* The first toc entry should be just after the ToC header */
Dan Handleye2712bc2014-04-10 15:37:22 +0100467 toc_entry = (fip_toc_entry_t *)(toc_header + 1);
Harry Liebelf58ad362014-01-10 18:00:33 +0000468
469 /* While the ToC entry is contained into the buffer */
470 int cnt = 0;
Dan Handleye2712bc2014-04-10 15:37:22 +0100471 while (((char *)toc_entry + sizeof(fip_toc_entry_t)) < fip_buffer_end) {
Harry Liebelf58ad362014-01-10 18:00:33 +0000472 cnt++;
473 /* Check if the ToC Entry is the last one */
474 if (compare_uuids(&toc_entry->uuid, &uuid_null) == 0) {
475 found_last_toc_entry = true;
476 status = 0;
477 break;
478 }
479
480 /* Add the entry into file_info */
481
482 /* Get the new entry in the array and clear it */
483 file_info_entry = &files[file_info_count++];
Dan Handleye2712bc2014-04-10 15:37:22 +0100484 memset(file_info_entry, 0, sizeof(file_info_t));
Harry Liebelf58ad362014-01-10 18:00:33 +0000485
486 /* Copy the info from the ToC entry */
487 copy_uuid(&file_info_entry->name_uuid, &toc_entry->uuid);
488 file_info_entry->image_buffer = fip_buffer +
489 toc_entry->offset_address;
490 file_info_entry->size = toc_entry->size;
491
492 /* Check if there is a corresponding entry in lookup table */
493 file_info_entry->entry =
494 get_entry_lookup_from_uuid(&toc_entry->uuid);
495
496 /* Go to the next ToC entry */
497 toc_entry++;
498 }
499
500 if (!found_last_toc_entry) {
501 printf("ERROR: Given FIP does not have an end ToC entry.\n");
502 status = EINVAL;
503 goto parse_fip_free;
504 } else {
505 /* All is well, we should not free any of the loaded images */
506 goto parse_fip_fclose;
507 }
508
509 parse_fip_free:
510 if (fip_buffer != NULL) {
511 free(fip_buffer);
512 fip_buffer = NULL;
513 }
514
515 parse_fip_fclose:
516 if (fip != NULL) {
517 fclose(fip);
518 }
519
520 parse_fip_return:
521 return status;
522}
523
524
525/* Parse all command-line options and return the FIP name if present. */
526static char *get_filename(int argc, char **argv, struct option *options)
527{
528 int c;
529 char *filename = NULL;
530
531 /* Reset option pointer so we parse all args. starts at 1.
532 * The filename is the only argument that does not have an option flag.
533 */
534 optind = 1;
535 while (1) {
Juan Castillo314a6082016-02-15 17:21:10 +0000536 c = getopt_long(argc, argv, OPT_STR, options, NULL);
Harry Liebelf58ad362014-01-10 18:00:33 +0000537 if (c == -1)
538 break;
539
540 if (c == '?') {
541 /* Failed to parse an option. Fail. */
542 return NULL;
543 }
544 }
545
546 /* Only one argument left then it is the filename.
547 * We dont expect any other options
548 */
Sandrine Bailleuxfce7a7d2014-03-19 13:39:52 +0000549 if (optind + 1 == argc)
Harry Liebelf58ad362014-01-10 18:00:33 +0000550 filename = argv[optind];
Harry Liebelf58ad362014-01-10 18:00:33 +0000551
552 return filename;
553}
554
555
556/* Work through command-line options */
Juan Castillo314a6082016-02-15 17:21:10 +0000557static int parse_cmdline(int argc, char **argv, struct option *options)
Harry Liebelf58ad362014-01-10 18:00:33 +0000558{
559 int c;
560 int status = 0;
561 int option_index = 0;
Dan Handleye2712bc2014-04-10 15:37:22 +0100562 entry_lookup_list_t *lookup_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000563
564 /* restart parse to process all options. starts at 1. */
565 optind = 1;
566 while (1) {
Juan Castillo314a6082016-02-15 17:21:10 +0000567 c = getopt_long(argc, argv, OPT_STR, options, &option_index);
Harry Liebelf58ad362014-01-10 18:00:33 +0000568 if (c == -1)
569 break;
570
571 switch (c) {
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000572 case OPT_TOC_ENTRY:
Harry Liebelf58ad362014-01-10 18:00:33 +0000573 if (optarg) {
574 /* Does the option expect a filename. */
575 lookup_entry = &toc_entry_lookup_list[option_index];
576 if (lookup_entry->flags & FLAG_FILENAME) {
577 status = add_file_info_entry(lookup_entry, optarg);
578 if (status != 0) {
579 printf("Failed to process %s\n",
580 options[option_index].name);
Kévin Petit90983a52014-12-08 13:23:09 +0000581 return status;
Harry Liebelf58ad362014-01-10 18:00:33 +0000582 } else {
583 /* Update package */
Juan Castillo314a6082016-02-15 17:21:10 +0000584 do_pack = 1;
Harry Liebelf58ad362014-01-10 18:00:33 +0000585 }
586 }
587 }
588 break;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000589
590 case OPT_DUMP:
591 do_dump = 1;
Juan Castillo314a6082016-02-15 17:21:10 +0000592 break;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000593
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000594 case OPT_HELP:
595 print_usage();
596 exit(0);
597
Harry Liebelf58ad362014-01-10 18:00:33 +0000598 default:
599 /* Unrecognised options are caught in get_filename() */
600 break;
601 }
602 }
603
Harry Liebelf58ad362014-01-10 18:00:33 +0000604 return status;
605
606}
607
608int main(int argc, char **argv)
609{
610 int i;
611 int status;
612 char *fip_filename;
Harry Liebelf58ad362014-01-10 18:00:33 +0000613
614 /* Clear file list table. */
615 memset(files, 0, sizeof(files));
616
617 /* Initialise for getopt_long().
618 * Use image table as defined at top of file to get options.
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000619 * Add 'dump' option, 'help' option and end marker.
Harry Liebelf58ad362014-01-10 18:00:33 +0000620 */
621 static struct option long_options[(sizeof(toc_entry_lookup_list)/
Dan Handleye2712bc2014-04-10 15:37:22 +0100622 sizeof(entry_lookup_list_t)) + 2];
Harry Liebelf58ad362014-01-10 18:00:33 +0000623
624 for (i = 0;
625 /* -1 because we dont want to process end marker in toc table */
Dan Handleye2712bc2014-04-10 15:37:22 +0100626 i < sizeof(toc_entry_lookup_list)/sizeof(entry_lookup_list_t) - 1;
Harry Liebelf58ad362014-01-10 18:00:33 +0000627 i++) {
628 long_options[i].name = toc_entry_lookup_list[i].command_line_name;
629 /* The only flag defined at the moment is for a FILENAME */
630 long_options[i].has_arg = toc_entry_lookup_list[i].flags ? 1 : 0;
631 long_options[i].flag = 0;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000632 long_options[i].val = OPT_TOC_ENTRY;
Harry Liebelf58ad362014-01-10 18:00:33 +0000633 }
634
635 /* Add '--dump' option */
636 long_options[i].name = "dump";
637 long_options[i].has_arg = 0;
638 long_options[i].flag = 0;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000639 long_options[i].val = OPT_DUMP;
Harry Liebelf58ad362014-01-10 18:00:33 +0000640
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000641 /* Add '--help' option */
642 long_options[++i].name = "help";
643 long_options[i].has_arg = 0;
644 long_options[i].flag = 0;
645 long_options[i].val = OPT_HELP;
646
Harry Liebelf58ad362014-01-10 18:00:33 +0000647 /* Zero the last entry (required) */
648 long_options[++i].name = 0;
649 long_options[i].has_arg = 0;
650 long_options[i].flag = 0;
651 long_options[i].val = 0;
652
653#ifdef DEBUG
654 /* Print all supported options */
655 for (i = 0; i < sizeof(long_options)/sizeof(struct option); i++) {
656 printf("long opt (%d) : name = %s\n", i, long_options[i].name);
657 }
658#endif /* DEBUG */
659
660 /* As the package may already exist and is to be updated we need to get
661 * the filename from the arguments and load from it.
662 * NOTE: As this is the first function to look at the program arguments
663 * it causes a failure if bad options were provided.
664 */
665 fip_filename = get_filename(argc, argv, long_options);
Harry Liebelf58ad362014-01-10 18:00:33 +0000666
667 /* Try to open the file and load it into memory */
Sandrine Bailleuxfce7a7d2014-03-19 13:39:52 +0000668 if (fip_filename != NULL) {
669 status = parse_fip(fip_filename);
670 if (status != 0) {
671 return status;
672 }
Harry Liebelf58ad362014-01-10 18:00:33 +0000673 }
674
675 /* Work through provided program arguments and perform actions */
Juan Castillo314a6082016-02-15 17:21:10 +0000676 status = parse_cmdline(argc, argv, long_options);
Harry Liebelf58ad362014-01-10 18:00:33 +0000677 if (status != 0) {
678 return status;
679 };
680
Sandrine Bailleuxfce7a7d2014-03-19 13:39:52 +0000681 if (fip_filename == NULL) {
682 printf("ERROR: Missing FIP filename\n");
683 print_usage();
684 return 0;
685 }
686
Harry Liebelf58ad362014-01-10 18:00:33 +0000687 /* Processed all command line options. Create/update the package if
688 * required.
689 */
690 if (do_pack) {
691 status = pack_images(fip_filename);
692 if (status != 0) {
693 printf("Failed to create package (status = %d).\n",
694 status);
695 }
696 }
697
Juan Castillo314a6082016-02-15 17:21:10 +0000698 /* Do not dump toc if we have an error as it could hide the error */
699 if ((status == 0) && (do_dump)) {
700 dump_toc();
701 }
702
Harry Liebelf58ad362014-01-10 18:00:33 +0000703 return status;
704}