blob: 7bce348a017ed782d20b30dff48118485b75f4ca [file] [log] [blame]
Harry Liebelf58ad362014-01-10 18:00:33 +00001/*
Juan Castillo937f3122016-02-15 17:21:10 +00002 * Copyright (c) 2014-2016, 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'
Juan Castillo937f3122016-02-15 17:21:10 +000045#define OPT_UNPACK 'u'
46#define OPT_FORCE 'f'
47#define OPT_STR "dfhu"
Sandrine Bailleux29e54422014-03-19 13:09:54 +000048
Juan Castillo314a6082016-02-15 17:21:10 +000049static file_info_t files[MAX_FILES];
50static unsigned file_info_count;
51static uuid_t uuid_null = {0};
52static int do_dump;
53static int do_pack;
Juan Castillo937f3122016-02-15 17:21:10 +000054static int do_unpack;
55static int do_force;
Harry Liebelf58ad362014-01-10 18:00:33 +000056
57/*
58 * TODO: Add ability to specify and flag different file types.
59 * Add flags to the toc_entry?
60 * const char* format_type_str[] = { "RAW", "ELF", "PIC" };
61 */
62
Harry Liebeleed7a5b2014-05-01 14:09:16 +010063/* The images used depends on the platform. */
Dan Handleye2712bc2014-04-10 15:37:22 +010064static entry_lookup_list_t toc_entry_lookup_list[] = {
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010065 { "SCP Firmware Updater Configuration FWU SCP_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_SCP_BL2U,
Juan Castillo8e04dec2016-01-05 11:55:36 +000066 "scp-fwu-cfg", NULL, FLAG_FILENAME },
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010067 { "AP Firmware Updater Configuration BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_BL2U,
Juan Castillo8e04dec2016-01-05 11:55:36 +000068 "ap-fwu-cfg", NULL, FLAG_FILENAME },
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010069 { "Firmware Updater NS_BL2U", UUID_TRUSTED_UPDATE_FIRMWARE_NS_BL2U,
Juan Castillo8e04dec2016-01-05 11:55:36 +000070 "fwu", NULL, FLAG_FILENAME },
Yatharth Kochar4dd39b82015-08-10 11:57:41 +010071 { "Non-Trusted Firmware Updater certificate", UUID_TRUSTED_FWU_CERT,
72 "fwu-cert", NULL, FLAG_FILENAME},
Harry Liebelf58ad362014-01-10 18:00:33 +000073 { "Trusted Boot Firmware BL2", UUID_TRUSTED_BOOT_FIRMWARE_BL2,
Juan Castillo8e04dec2016-01-05 11:55:36 +000074 "tb-fw", NULL, FLAG_FILENAME },
Juan Castilloa72b6472015-12-10 15:49:17 +000075 { "SCP Firmware SCP_BL2", UUID_SCP_FIRMWARE_SCP_BL2,
Juan Castillo8e04dec2016-01-05 11:55:36 +000076 "scp-fw", NULL, FLAG_FILENAME},
Juan Castillo7d199412015-12-14 09:35:25 +000077 { "EL3 Runtime Firmware BL31", UUID_EL3_RUNTIME_FIRMWARE_BL31,
Juan Castillo8e04dec2016-01-05 11:55:36 +000078 "soc-fw", NULL, FLAG_FILENAME},
Juan Castillo7d199412015-12-14 09:35:25 +000079 { "Secure Payload BL32 (Trusted OS)", UUID_SECURE_PAYLOAD_BL32,
Juan Castillo8e04dec2016-01-05 11:55:36 +000080 "tos-fw", NULL, FLAG_FILENAME},
Juan Castillo7d199412015-12-14 09:35:25 +000081 { "Non-Trusted Firmware BL33", UUID_NON_TRUSTED_FIRMWARE_BL33,
Juan Castillo8e04dec2016-01-05 11:55:36 +000082 "nt-fw", NULL, FLAG_FILENAME},
Juan Castillo379954c2014-11-04 17:36:40 +000083 /* Key Certificates */
84 { "Root Of Trust key certificate", UUID_ROT_KEY_CERT,
85 "rot-cert", NULL, FLAG_FILENAME },
86 { "Trusted key certificate", UUID_TRUSTED_KEY_CERT,
87 "trusted-key-cert", NULL, FLAG_FILENAME},
Juan Castillobe801202015-12-03 10:19:21 +000088 { "SCP Firmware key certificate", UUID_SCP_FW_KEY_CERT,
89 "scp-fw-key-cert", NULL, FLAG_FILENAME},
90 { "SoC Firmware key certificate", UUID_SOC_FW_KEY_CERT,
91 "soc-fw-key-cert", NULL, FLAG_FILENAME},
92 { "Trusted OS Firmware key certificate", UUID_TRUSTED_OS_FW_KEY_CERT,
93 "tos-fw-key-cert", NULL, FLAG_FILENAME},
94 { "Non-Trusted Firmware key certificate", UUID_NON_TRUSTED_FW_KEY_CERT,
95 "nt-fw-key-cert", NULL, FLAG_FILENAME},
Juan Castillo379954c2014-11-04 17:36:40 +000096 /* Content certificates */
Juan Castillobe801202015-12-03 10:19:21 +000097 { "Trusted Boot Firmware BL2 certificate", UUID_TRUSTED_BOOT_FW_CERT,
98 "tb-fw-cert", NULL, FLAG_FILENAME },
99 { "SCP Firmware content certificate", UUID_SCP_FW_CONTENT_CERT,
100 "scp-fw-cert", NULL, FLAG_FILENAME},
101 { "SoC Firmware content certificate", UUID_SOC_FW_CONTENT_CERT,
102 "soc-fw-cert", NULL, FLAG_FILENAME},
103 { "Trusted OS Firmware content certificate", UUID_TRUSTED_OS_FW_CONTENT_CERT,
104 "tos-fw-cert", NULL, FLAG_FILENAME},
105 { "Non-Trusted Firmware content certificate", UUID_NON_TRUSTED_FW_CONTENT_CERT,
106 "nt-fw-cert", NULL, FLAG_FILENAME},
Harry Liebelf58ad362014-01-10 18:00:33 +0000107 { NULL, {0}, 0 }
108};
109
110
111/* Return 0 for equal uuids */
112static inline int compare_uuids(const uuid_t *uuid1, const uuid_t *uuid2)
113{
114 return memcmp(uuid1, uuid2, sizeof(uuid_t));
115}
116
117
118static inline void copy_uuid(uuid_t *to_uuid, const uuid_t *from_uuid)
119{
120 memcpy(to_uuid, from_uuid, sizeof(uuid_t));
121}
122
123
124static void print_usage(void)
125{
Dan Handleye2712bc2014-04-10 15:37:22 +0100126 entry_lookup_list_t *entry = toc_entry_lookup_list;
Harry Liebelf58ad362014-01-10 18:00:33 +0000127
Juan Castillo314a6082016-02-15 17:21:10 +0000128 printf("\nThis tool is used to create a Firmware Image Package.\n\n");
129 printf("Usage:\n");
130 printf("\tfip_create [options] FIP_FILENAME\n\n");
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000131 printf("Options:\n");
Juan Castillo314a6082016-02-15 17:21:10 +0000132 printf("\t-h,--help: Print this help message and exit\n");
133 printf("\t-d,--dump: Print contents of FIP after update\n");
Juan Castillo937f3122016-02-15 17:21:10 +0000134 printf("\t-u,--unpack: Unpack images from an existing FIP\n");
135 printf("\t-f,--force: Overwrite existing files when unpacking images\n\n");
Juan Castillo314a6082016-02-15 17:21:10 +0000136 printf("Components that can be added/updated:\n");
Harry Liebelf58ad362014-01-10 18:00:33 +0000137 for (; entry->command_line_name != NULL; entry++) {
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000138 printf("\t--%s%s\t\t%s",
139 entry->command_line_name,
140 (entry->flags & FLAG_FILENAME) ? " FILENAME" : "",
141 entry->name);
142 printf("\n");
Harry Liebelf58ad362014-01-10 18:00:33 +0000143 }
Juan Castillo314a6082016-02-15 17:21:10 +0000144 printf("\n");
Harry Liebelf58ad362014-01-10 18:00:33 +0000145}
146
147
Dan Handleye2712bc2014-04-10 15:37:22 +0100148static entry_lookup_list_t *get_entry_lookup_from_uuid(const uuid_t *uuid)
Harry Liebelf58ad362014-01-10 18:00:33 +0000149{
150 unsigned int lookup_index = 0;
151
152 while (toc_entry_lookup_list[lookup_index].command_line_name != NULL) {
153 if (compare_uuids(&toc_entry_lookup_list[lookup_index].name_uuid,
154 uuid) == 0) {
155 return &toc_entry_lookup_list[lookup_index];
156 }
157 lookup_index++;
158 }
159 return NULL;
160}
161
162
Dan Handleye2712bc2014-04-10 15:37:22 +0100163static file_info_t *find_file_info_from_uuid(const uuid_t *uuid)
Harry Liebelf58ad362014-01-10 18:00:33 +0000164{
165 int index;
166
167 for (index = 0; index < file_info_count; index++) {
168 if (compare_uuids(&files[index].name_uuid, uuid) == 0) {
169 return &files[index];
170 }
171 }
172 return NULL;
173}
174
175
Dan Handleye2712bc2014-04-10 15:37:22 +0100176static int add_file_info_entry(entry_lookup_list_t *lookup_entry, char *filename)
Harry Liebelf58ad362014-01-10 18:00:33 +0000177{
Dan Handleye2712bc2014-04-10 15:37:22 +0100178 file_info_t *file_info_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000179 int error;
180 struct stat file_status;
181 bool is_new_entry = false;
182
183 /* Check if the file already exists in the array */
184 file_info_entry = find_file_info_from_uuid(&lookup_entry->name_uuid);
185 if (file_info_entry == NULL) {
186 /* The file does not exist in the current list; take the next
187 * one available in the file_info list. 'file_info_count' is
188 * incremented in case of successful update at the end of the
189 * function.
190 */
191 file_info_entry = &files[file_info_count];
192 is_new_entry = true;
193
194 /* Copy the uuid for the new entry */
195 copy_uuid(&file_info_entry->name_uuid,
196 &lookup_entry->name_uuid);
197 }
198
199 /* Get the file information for entry */
200 error = stat(filename, &file_status);
201 if (error != 0) {
202 printf("Error: Cannot get information for file \"%s\": %s\n",
203 filename, strerror(errno));
204 return errno;
205 }
206 file_info_entry->filename = filename;
207 file_info_entry->size = (unsigned int)file_status.st_size;
208 file_info_entry->entry = lookup_entry;
209
210 /* Increment the file_info counter on success if it is new file entry */
211 if (is_new_entry) {
212 file_info_count++;
213
214 /* Ensure we do not overflow */
215 if (file_info_count > MAX_FILES) {
216 printf("ERROR: Too many files in Package\n");
217 return 1;
218 }
219 }
220
221 return 0;
222}
223
224
225static int write_memory_to_file(const uint8_t *start, const char *filename,
226 unsigned int size)
227{
228 FILE *stream;
229 unsigned int bytes_written;
230
231 /* Write the packed file out to the filesystem */
232 stream = fopen(filename, "r+");
233 if (stream == NULL) {
234 stream = fopen(filename, "w");
235 if (stream == NULL) {
236 printf("Error: Cannot create output file \"%s\": %s\n",
237 filename, strerror(errno));
238 return errno;
239 } else {
240 printf("Creating \"%s\"\n", filename);
241 }
242 } else {
243 printf("Updating \"%s\"\n", filename);
244 }
245
246 bytes_written = fwrite(start, sizeof(uint8_t), size, stream);
247 fclose(stream);
248
249 if (bytes_written != size) {
250 printf("Error: Incorrect write for file \"%s\": Size=%u,"
251 "Written=%u bytes.\n", filename, size, bytes_written);
252 return EIO;
253 }
254
255 return 0;
256}
257
258
Dan Handleye2712bc2014-04-10 15:37:22 +0100259static int read_file_to_memory(void *memory, const file_info_t *info)
Harry Liebelf58ad362014-01-10 18:00:33 +0000260{
261 FILE *stream;
262 unsigned int bytes_read;
263
264 /* If the file_info is defined by its filename we need to load it */
265 if (info->filename) {
266 /* Read image from filesystem */
267 stream = fopen(info->filename, "r");
268 if (stream == NULL) {
269 printf("Error: Cannot open file \"%s\": %s\n",
270 info->filename, strerror(errno));
271 return errno;
272 }
273
274 bytes_read = (unsigned int)fread(memory, sizeof(uint8_t),
275 info->size, stream);
276 fclose(stream);
277 if (bytes_read != info->size) {
278 printf("Error: Incomplete read for file \"%s\":"
279 "Size=%u, Read=%u bytes.\n", info->filename,
280 info->size, bytes_read);
281 return EIO;
282 }
283 } else {
284 if (info->image_buffer == NULL) {
285 printf("ERROR: info->image_buffer = NULL\n");
286 return EIO;
287 }
288 /* Copy the file_info buffer (extracted from the existing
289 * image package) into the new buffer.
290 */
291 memcpy(memory, info->image_buffer, info->size);
292 }
293
294 return 0;
295}
296
297
298/* Create the image package file */
299static int pack_images(const char *fip_filename)
300{
301 int status;
302 uint8_t *fip_base_address;
303 void *entry_address;
Dan Handleye2712bc2014-04-10 15:37:22 +0100304 fip_toc_header_t *toc_header;
305 fip_toc_entry_t *toc_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000306 unsigned int entry_index;
307 unsigned int toc_size;
308 unsigned int fip_size;
309 unsigned int entry_offset_address;
310 unsigned int payload_size = 0;
311
312 /* Validate filename */
313 if ((fip_filename == NULL) || (strcmp(fip_filename, "") == 0)) {
314 return EINVAL;
315 }
316
317 /* Payload size calculation */
318 for (entry_index = 0; entry_index < file_info_count; entry_index++) {
319 payload_size += files[entry_index].size;
320 }
321
322 /* Allocate memory for entire package, including the final null entry */
Dan Handleye2712bc2014-04-10 15:37:22 +0100323 toc_size = (sizeof(fip_toc_header_t) +
324 (sizeof(fip_toc_entry_t) * (file_info_count + 1)));
Harry Liebelf58ad362014-01-10 18:00:33 +0000325 fip_size = toc_size + payload_size;
326 fip_base_address = malloc(fip_size);
327 if (fip_base_address == NULL) {
328 printf("Error: Can't allocate enough memory to create package."
329 "Process aborted.\n");
330 return ENOMEM;
331 }
332 memset(fip_base_address, 0, fip_size);
333
334 /* Create ToC Header */
Dan Handleye2712bc2014-04-10 15:37:22 +0100335 toc_header = (fip_toc_header_t *)fip_base_address;
Harry Liebelf58ad362014-01-10 18:00:33 +0000336 toc_header->name = TOC_HEADER_NAME;
337 toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER;
338 toc_header->flags = 0;
339
Dan Handleye2712bc2014-04-10 15:37:22 +0100340 toc_entry = (fip_toc_entry_t *)(fip_base_address +
341 sizeof(fip_toc_header_t));
Harry Liebelf58ad362014-01-10 18:00:33 +0000342
343 /* Calculate the starting address of the first image, right after the
344 * toc header.
345 */
346 entry_offset_address = toc_size;
347 entry_index = 0;
348
349 /* Create the package in memory. */
350 for (entry_index = 0; entry_index < file_info_count; entry_index++) {
351 entry_address = (fip_base_address + entry_offset_address);
352 status = read_file_to_memory(entry_address,
353 &files[entry_index]);
354 if (status != 0) {
355 printf("Error: While reading \"%s\" from filesystem.\n",
356 files[entry_index].filename);
357 return status;
358 }
359
360 copy_uuid(&toc_entry->uuid, &files[entry_index].name_uuid);
361 toc_entry->offset_address = entry_offset_address;
362 toc_entry->size = files[entry_index].size;
363 toc_entry->flags = 0;
364 entry_offset_address += toc_entry->size;
365 toc_entry++;
366 }
367
368 /* Add a null uuid entry to mark the end of toc entries */
369 copy_uuid(&toc_entry->uuid, &uuid_null);
370 toc_entry->offset_address = entry_offset_address;
371 toc_entry->size = 0;
372 toc_entry->flags = 0;
373
374 /* Save the package to file */
375 status = write_memory_to_file(fip_base_address, fip_filename, fip_size);
376 if (status != 0) {
377 printf("Error: Failed while writing package to file \"%s\" "
378 "with status=%d.\n", fip_filename, status);
379 return status;
380 }
381 return 0;
382}
383
384
Juan Castillo937f3122016-02-15 17:21:10 +0000385/*
386 * Unpack all images from an existing FIP
387 *
388 * Images will be unpacked into the working directory using filenames as
389 * specified by the corresponding command line option plus the 'bin' extension.
390 * For example, the image specified by the --soc-fw option will be unpacked as
391 * 'soc-fw.bin'
392 */
393static int unpack_images(void)
394{
395 FILE *stream;
396 size_t bytes_written;
397 file_info_t *file_info;
398 char *filename[MAX_FILES];
399 int status, ret = 0;
400 unsigned int i, idx, num_img;
401 struct stat st;
402 size_t len;
403
404 /* Make the output filenames */
405 for (idx = 0; idx < file_info_count; idx++) {
406 filename[idx] = NULL;
407 file_info = &files[idx];
408 if (file_info->image_buffer == NULL) {
409 continue;
410 }
411 len = strlen(file_info->entry->command_line_name);
412 filename[idx] = malloc(len + 5); /* ".bin" + '\0' */
413 if (filename[idx] == NULL) {
414 printf("ERROR: out of memory\n");
415 for (i = 0; i < idx; i++) {
416 free(filename[i]);
417 }
418 return ENOMEM;
419 }
420 strcpy(filename[idx], file_info->entry->command_line_name);
421 strcat(filename[idx], ".bin");
422 }
423
424
425 /* Check if output files already exist in the filesystem. We perform
426 * this check before any other action, so if any of the files
427 * exists, nothing is unpacked. If force overwrite is enabled, we skip
428 * this check */
429 if (!do_force) {
430 for (idx = 0; idx < file_info_count; idx++) {
431 file_info = &files[idx];
432 if (file_info->image_buffer == NULL) {
433 continue;
434 }
435 status = stat(filename[idx], &st);
436 if (!status) {
437 printf("File '%s' exists. Use --force to overwrite.\n",
438 filename[idx]);
439 printf("Process aborted.\n");
440 ret = EEXIST;
441 goto unpack_images_free;
442 }
443 }
444 }
445
446 printf("Unpacking images...\n");
447
448 /* Write the images to files */
449 num_img = 0;
450 for (idx = 0; idx < file_info_count; idx++) {
451 file_info = &files[idx];
452 if (file_info->image_buffer == NULL) {
453 continue;
454 }
455 /* Unpack the image to a file */
456 stream = fopen(filename[idx], "w");
457 if (!stream) {
458 printf("ERROR: cannot open '%s' for writing\n",
459 filename[idx]);
460 ret = EIO;
461 goto unpack_images_free;
462 }
463 bytes_written = fwrite(file_info->image_buffer, sizeof(uint8_t),
464 file_info->size, stream);
465 fclose(stream);
466
467 if (bytes_written != file_info->size) {
468 printf("ERROR: Incorrect write for file \"%s\": Size=%u,"
469 "Written=%lu bytes.\n", filename[idx], file_info->size,
470 bytes_written);
471 ret = EIO;
472 goto unpack_images_free;
473 }
474 num_img++;
475 }
476
477 printf("Done. %u images unpacked\n", num_img);
478
479unpack_images_free:
480 for (idx = 0; idx < file_info_count; idx++) {
481 free(filename[idx]);
482 }
483
484 return ret;
485}
486
487
Harry Liebelf58ad362014-01-10 18:00:33 +0000488static void dump_toc(void)
489{
490 unsigned int index = 0;
491 unsigned int image_offset;
492 unsigned int image_size = 0;
493
Dan Handleye2712bc2014-04-10 15:37:22 +0100494 image_offset = sizeof(fip_toc_header_t) +
495 (sizeof(fip_toc_entry_t) * (file_info_count + 1));
Harry Liebelf58ad362014-01-10 18:00:33 +0000496
497 printf("Firmware Image Package ToC:\n");
498 printf("---------------------------\n");
499 for (index = 0; index < file_info_count; index++) {
500 if (files[index].entry) {
501 printf("- %s: ", files[index].entry->name);
502 } else {
503 printf("- Unknown entry: ");
504 }
505 image_size = files[index].size;
506
507 printf("offset=0x%X, size=0x%X\n", image_offset, image_size);
508 image_offset += image_size;
509
510 if (files[index].filename) {
511 printf(" file: '%s'\n", files[index].filename);
512 }
513 }
514 printf("---------------------------\n");
515}
516
517
518/* Read and load existing package into memory. */
519static int parse_fip(const char *fip_filename)
520{
521 FILE *fip;
522 char *fip_buffer;
523 char *fip_buffer_end;
524 int fip_size, read_fip_size;
Dan Handleye2712bc2014-04-10 15:37:22 +0100525 fip_toc_header_t *toc_header;
526 fip_toc_entry_t *toc_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000527 bool found_last_toc_entry = false;
Dan Handleye2712bc2014-04-10 15:37:22 +0100528 file_info_t *file_info_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000529 int status = -1;
530 struct stat st;
531
532 fip = fopen(fip_filename, "r");
533 if (fip == NULL) {
534 /* If the fip does not exist just return, it should not be
535 * considered as an error. The package will be created later
536 */
537 status = 0;
538 goto parse_fip_return;
539 }
540
541 if (stat(fip_filename, &st) != 0) {
542 status = errno;
543 goto parse_fip_fclose;
544 } else {
545 fip_size = (int)st.st_size;
546 }
547
548 /* Allocate a buffer to read the package */
549 fip_buffer = (char *)malloc(fip_size);
550 if (fip_buffer == NULL) {
551 printf("ERROR: Cannot allocate %d bytes.\n", fip_size);
552 status = errno;
553 goto parse_fip_fclose;
554 }
555 fip_buffer_end = fip_buffer + fip_size;
556
557 /* Read the file */
558 read_fip_size = fread(fip_buffer, sizeof(char), fip_size, fip);
559 if (read_fip_size != fip_size) {
560 printf("ERROR: Cannot read the FIP.\n");
561 status = EIO;
562 goto parse_fip_free;
563 }
564 fclose(fip);
565 fip = NULL;
566
567 /* The package must at least contain the ToC Header */
Dan Handleye2712bc2014-04-10 15:37:22 +0100568 if (fip_size < sizeof(fip_toc_header_t)) {
Harry Liebelf58ad362014-01-10 18:00:33 +0000569 printf("ERROR: Given FIP is smaller than the ToC header.\n");
570 status = EINVAL;
571 goto parse_fip_free;
572 }
573 /* Set the ToC Header at the base of the buffer */
Dan Handleye2712bc2014-04-10 15:37:22 +0100574 toc_header = (fip_toc_header_t *)fip_buffer;
Harry Liebelf58ad362014-01-10 18:00:33 +0000575 /* The first toc entry should be just after the ToC header */
Dan Handleye2712bc2014-04-10 15:37:22 +0100576 toc_entry = (fip_toc_entry_t *)(toc_header + 1);
Harry Liebelf58ad362014-01-10 18:00:33 +0000577
578 /* While the ToC entry is contained into the buffer */
579 int cnt = 0;
Dan Handleye2712bc2014-04-10 15:37:22 +0100580 while (((char *)toc_entry + sizeof(fip_toc_entry_t)) < fip_buffer_end) {
Harry Liebelf58ad362014-01-10 18:00:33 +0000581 cnt++;
582 /* Check if the ToC Entry is the last one */
583 if (compare_uuids(&toc_entry->uuid, &uuid_null) == 0) {
584 found_last_toc_entry = true;
585 status = 0;
586 break;
587 }
588
589 /* Add the entry into file_info */
590
591 /* Get the new entry in the array and clear it */
592 file_info_entry = &files[file_info_count++];
Dan Handleye2712bc2014-04-10 15:37:22 +0100593 memset(file_info_entry, 0, sizeof(file_info_t));
Harry Liebelf58ad362014-01-10 18:00:33 +0000594
595 /* Copy the info from the ToC entry */
596 copy_uuid(&file_info_entry->name_uuid, &toc_entry->uuid);
597 file_info_entry->image_buffer = fip_buffer +
598 toc_entry->offset_address;
599 file_info_entry->size = toc_entry->size;
600
601 /* Check if there is a corresponding entry in lookup table */
602 file_info_entry->entry =
603 get_entry_lookup_from_uuid(&toc_entry->uuid);
604
605 /* Go to the next ToC entry */
606 toc_entry++;
607 }
608
609 if (!found_last_toc_entry) {
610 printf("ERROR: Given FIP does not have an end ToC entry.\n");
611 status = EINVAL;
612 goto parse_fip_free;
613 } else {
614 /* All is well, we should not free any of the loaded images */
615 goto parse_fip_fclose;
616 }
617
618 parse_fip_free:
619 if (fip_buffer != NULL) {
620 free(fip_buffer);
621 fip_buffer = NULL;
622 }
623
624 parse_fip_fclose:
625 if (fip != NULL) {
626 fclose(fip);
627 }
628
629 parse_fip_return:
630 return status;
631}
632
633
634/* Parse all command-line options and return the FIP name if present. */
635static char *get_filename(int argc, char **argv, struct option *options)
636{
637 int c;
638 char *filename = NULL;
639
640 /* Reset option pointer so we parse all args. starts at 1.
641 * The filename is the only argument that does not have an option flag.
642 */
643 optind = 1;
644 while (1) {
Juan Castillo314a6082016-02-15 17:21:10 +0000645 c = getopt_long(argc, argv, OPT_STR, options, NULL);
Harry Liebelf58ad362014-01-10 18:00:33 +0000646 if (c == -1)
647 break;
648
649 if (c == '?') {
650 /* Failed to parse an option. Fail. */
651 return NULL;
652 }
653 }
654
655 /* Only one argument left then it is the filename.
656 * We dont expect any other options
657 */
Sandrine Bailleuxfce7a7d2014-03-19 13:39:52 +0000658 if (optind + 1 == argc)
Harry Liebelf58ad362014-01-10 18:00:33 +0000659 filename = argv[optind];
Harry Liebelf58ad362014-01-10 18:00:33 +0000660
661 return filename;
662}
663
664
665/* Work through command-line options */
Juan Castillo314a6082016-02-15 17:21:10 +0000666static int parse_cmdline(int argc, char **argv, struct option *options)
Harry Liebelf58ad362014-01-10 18:00:33 +0000667{
668 int c;
669 int status = 0;
670 int option_index = 0;
Dan Handleye2712bc2014-04-10 15:37:22 +0100671 entry_lookup_list_t *lookup_entry;
Harry Liebelf58ad362014-01-10 18:00:33 +0000672
673 /* restart parse to process all options. starts at 1. */
674 optind = 1;
675 while (1) {
Juan Castillo314a6082016-02-15 17:21:10 +0000676 c = getopt_long(argc, argv, OPT_STR, options, &option_index);
Harry Liebelf58ad362014-01-10 18:00:33 +0000677 if (c == -1)
678 break;
679
680 switch (c) {
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000681 case OPT_TOC_ENTRY:
Harry Liebelf58ad362014-01-10 18:00:33 +0000682 if (optarg) {
683 /* Does the option expect a filename. */
684 lookup_entry = &toc_entry_lookup_list[option_index];
685 if (lookup_entry->flags & FLAG_FILENAME) {
686 status = add_file_info_entry(lookup_entry, optarg);
687 if (status != 0) {
688 printf("Failed to process %s\n",
689 options[option_index].name);
Kévin Petit90983a52014-12-08 13:23:09 +0000690 return status;
Harry Liebelf58ad362014-01-10 18:00:33 +0000691 } else {
692 /* Update package */
Juan Castillo314a6082016-02-15 17:21:10 +0000693 do_pack = 1;
Harry Liebelf58ad362014-01-10 18:00:33 +0000694 }
695 }
696 }
697 break;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000698
699 case OPT_DUMP:
700 do_dump = 1;
Juan Castillo314a6082016-02-15 17:21:10 +0000701 break;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000702
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000703 case OPT_HELP:
704 print_usage();
705 exit(0);
706
Juan Castillo937f3122016-02-15 17:21:10 +0000707 case OPT_UNPACK:
708 do_unpack = 1;
709 break;
710
711 case OPT_FORCE:
712 do_force = 1;
713 break;
714
Harry Liebelf58ad362014-01-10 18:00:33 +0000715 default:
716 /* Unrecognised options are caught in get_filename() */
717 break;
718 }
719 }
720
Harry Liebelf58ad362014-01-10 18:00:33 +0000721 return status;
722
723}
724
725int main(int argc, char **argv)
726{
727 int i;
728 int status;
729 char *fip_filename;
Juan Castillo937f3122016-02-15 17:21:10 +0000730 struct stat st;
Harry Liebelf58ad362014-01-10 18:00:33 +0000731
732 /* Clear file list table. */
733 memset(files, 0, sizeof(files));
734
735 /* Initialise for getopt_long().
736 * Use image table as defined at top of file to get options.
Juan Castillo937f3122016-02-15 17:21:10 +0000737 * Add common options and end marker.
Harry Liebelf58ad362014-01-10 18:00:33 +0000738 */
739 static struct option long_options[(sizeof(toc_entry_lookup_list)/
Juan Castillo937f3122016-02-15 17:21:10 +0000740 sizeof(entry_lookup_list_t)) + 4];
Harry Liebelf58ad362014-01-10 18:00:33 +0000741
742 for (i = 0;
743 /* -1 because we dont want to process end marker in toc table */
Dan Handleye2712bc2014-04-10 15:37:22 +0100744 i < sizeof(toc_entry_lookup_list)/sizeof(entry_lookup_list_t) - 1;
Harry Liebelf58ad362014-01-10 18:00:33 +0000745 i++) {
746 long_options[i].name = toc_entry_lookup_list[i].command_line_name;
747 /* The only flag defined at the moment is for a FILENAME */
748 long_options[i].has_arg = toc_entry_lookup_list[i].flags ? 1 : 0;
749 long_options[i].flag = 0;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000750 long_options[i].val = OPT_TOC_ENTRY;
Harry Liebelf58ad362014-01-10 18:00:33 +0000751 }
752
753 /* Add '--dump' option */
754 long_options[i].name = "dump";
755 long_options[i].has_arg = 0;
756 long_options[i].flag = 0;
Sandrine Bailleux29e54422014-03-19 13:09:54 +0000757 long_options[i].val = OPT_DUMP;
Harry Liebelf58ad362014-01-10 18:00:33 +0000758
Sandrine Bailleux8c60fee2014-03-19 13:21:42 +0000759 /* Add '--help' option */
760 long_options[++i].name = "help";
761 long_options[i].has_arg = 0;
762 long_options[i].flag = 0;
763 long_options[i].val = OPT_HELP;
764
Juan Castillo937f3122016-02-15 17:21:10 +0000765 /* Add '--unpack' option */
766 long_options[++i].name = "unpack";
767 long_options[i].has_arg = 0;
768 long_options[i].flag = 0;
769 long_options[i].val = OPT_UNPACK;
770
771 /* Add '--force' option */
772 long_options[++i].name = "force";
773 long_options[i].has_arg = 0;
774 long_options[i].flag = 0;
775 long_options[i].val = OPT_FORCE;
776
Harry Liebelf58ad362014-01-10 18:00:33 +0000777 /* Zero the last entry (required) */
778 long_options[++i].name = 0;
779 long_options[i].has_arg = 0;
780 long_options[i].flag = 0;
781 long_options[i].val = 0;
782
783#ifdef DEBUG
784 /* Print all supported options */
785 for (i = 0; i < sizeof(long_options)/sizeof(struct option); i++) {
786 printf("long opt (%d) : name = %s\n", i, long_options[i].name);
787 }
788#endif /* DEBUG */
789
790 /* As the package may already exist and is to be updated we need to get
791 * the filename from the arguments and load from it.
792 * NOTE: As this is the first function to look at the program arguments
793 * it causes a failure if bad options were provided.
794 */
795 fip_filename = get_filename(argc, argv, long_options);
Harry Liebelf58ad362014-01-10 18:00:33 +0000796
797 /* Try to open the file and load it into memory */
Sandrine Bailleuxfce7a7d2014-03-19 13:39:52 +0000798 if (fip_filename != NULL) {
799 status = parse_fip(fip_filename);
800 if (status != 0) {
801 return status;
802 }
Harry Liebelf58ad362014-01-10 18:00:33 +0000803 }
804
805 /* Work through provided program arguments and perform actions */
Juan Castillo314a6082016-02-15 17:21:10 +0000806 status = parse_cmdline(argc, argv, long_options);
Harry Liebelf58ad362014-01-10 18:00:33 +0000807 if (status != 0) {
808 return status;
809 };
810
Sandrine Bailleuxfce7a7d2014-03-19 13:39:52 +0000811 if (fip_filename == NULL) {
812 printf("ERROR: Missing FIP filename\n");
813 print_usage();
814 return 0;
815 }
816
Juan Castillo937f3122016-02-15 17:21:10 +0000817 /* Unpack images from FIP always takes precedence over packaging. In
818 * the future, there will be different commands for each action and
819 * only one will be specified in the command line */
820 if (do_unpack) {
821 status = stat(fip_filename, &st);
822 if (status != 0) {
823 printf("ERROR: cannot open %s\n", fip_filename);
824 return status;
825 }
826 /* Warning if user has specified images */
827 if (do_pack) {
828 printf("WARNING: Unpack option specified. Input images "
829 "will be ignored.\n");
830 }
831 status = unpack_images();
832 if (status != 0) {
833 printf("ERROR: failed to unpack package (status = %d).\n",
834 status);
835 return status;
836 }
837 } else if (do_pack) {
838 /* Create/update FIP */
Harry Liebelf58ad362014-01-10 18:00:33 +0000839 status = pack_images(fip_filename);
840 if (status != 0) {
841 printf("Failed to create package (status = %d).\n",
842 status);
843 }
844 }
845
Juan Castillo314a6082016-02-15 17:21:10 +0000846 /* Do not dump toc if we have an error as it could hide the error */
847 if ((status == 0) && (do_dump)) {
848 dump_toc();
849 }
850
Harry Liebelf58ad362014-01-10 18:00:33 +0000851 return status;
852}