summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authordanh-arm <dan.handley@arm.com>2016-04-07 17:16:27 +0100
committerdanh-arm <dan.handley@arm.com>2016-04-07 17:16:27 +0100
commite8508834747aebd843ed56627c646acb6136d8e1 (patch)
tree27a9b9f6b0efaa15f0989ba753ff5c69cd414aac /tools
parent91e8ae66310142e9a62cb5fb45ade83d434acf95 (diff)
parentc49a805d97849cc18162fdc7f100547417c58890 (diff)
Merge pull request #582 from jcastillo-arm/jc/fip_extract
fip_create: add support for image unpacking
Diffstat (limited to 'tools')
-rw-r--r--tools/fip_create/fip_create.c215
1 files changed, 182 insertions, 33 deletions
diff --git a/tools/fip_create/fip_create.c b/tools/fip_create/fip_create.c
index 19afc748..7bce348a 100644
--- a/tools/fip_create/fip_create.c
+++ b/tools/fip_create/fip_create.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2014-2016, ARM Limited and Contributors. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -40,12 +40,19 @@
/* Values returned by getopt() as part of the command line parsing */
#define OPT_TOC_ENTRY 0
-#define OPT_DUMP 1
-#define OPT_HELP 2
-
-file_info_t files[MAX_FILES];
-unsigned file_info_count = 0;
-uuid_t uuid_null = {0};
+#define OPT_DUMP 'd'
+#define OPT_HELP 'h'
+#define OPT_UNPACK 'u'
+#define OPT_FORCE 'f'
+#define OPT_STR "dfhu"
+
+static file_info_t files[MAX_FILES];
+static unsigned file_info_count;
+static uuid_t uuid_null = {0};
+static int do_dump;
+static int do_pack;
+static int do_unpack;
+static int do_force;
/*
* TODO: Add ability to specify and flag different file types.
@@ -118,12 +125,15 @@ static void print_usage(void)
{
entry_lookup_list_t *entry = toc_entry_lookup_list;
- printf("Usage: fip_create [options] FIP_FILENAME\n\n");
- printf("\tThis tool is used to create a Firmware Image Package.\n\n");
+ printf("\nThis tool is used to create a Firmware Image Package.\n\n");
+ printf("Usage:\n");
+ printf("\tfip_create [options] FIP_FILENAME\n\n");
printf("Options:\n");
- printf("\t--help: Print this help message and exit\n");
- printf("\t--dump: Print contents of FIP\n\n");
- printf("\tComponents that can be added/updated:\n");
+ printf("\t-h,--help: Print this help message and exit\n");
+ printf("\t-d,--dump: Print contents of FIP after update\n");
+ printf("\t-u,--unpack: Unpack images from an existing FIP\n");
+ printf("\t-f,--force: Overwrite existing files when unpacking images\n\n");
+ printf("Components that can be added/updated:\n");
for (; entry->command_line_name != NULL; entry++) {
printf("\t--%s%s\t\t%s",
entry->command_line_name,
@@ -131,6 +141,7 @@ static void print_usage(void)
entry->name);
printf("\n");
}
+ printf("\n");
}
@@ -371,6 +382,109 @@ static int pack_images(const char *fip_filename)
}
+/*
+ * Unpack all images from an existing FIP
+ *
+ * Images will be unpacked into the working directory using filenames as
+ * specified by the corresponding command line option plus the 'bin' extension.
+ * For example, the image specified by the --soc-fw option will be unpacked as
+ * 'soc-fw.bin'
+ */
+static int unpack_images(void)
+{
+ FILE *stream;
+ size_t bytes_written;
+ file_info_t *file_info;
+ char *filename[MAX_FILES];
+ int status, ret = 0;
+ unsigned int i, idx, num_img;
+ struct stat st;
+ size_t len;
+
+ /* Make the output filenames */
+ for (idx = 0; idx < file_info_count; idx++) {
+ filename[idx] = NULL;
+ file_info = &files[idx];
+ if (file_info->image_buffer == NULL) {
+ continue;
+ }
+ len = strlen(file_info->entry->command_line_name);
+ filename[idx] = malloc(len + 5); /* ".bin" + '\0' */
+ if (filename[idx] == NULL) {
+ printf("ERROR: out of memory\n");
+ for (i = 0; i < idx; i++) {
+ free(filename[i]);
+ }
+ return ENOMEM;
+ }
+ strcpy(filename[idx], file_info->entry->command_line_name);
+ strcat(filename[idx], ".bin");
+ }
+
+
+ /* Check if output files already exist in the filesystem. We perform
+ * this check before any other action, so if any of the files
+ * exists, nothing is unpacked. If force overwrite is enabled, we skip
+ * this check */
+ if (!do_force) {
+ for (idx = 0; idx < file_info_count; idx++) {
+ file_info = &files[idx];
+ if (file_info->image_buffer == NULL) {
+ continue;
+ }
+ status = stat(filename[idx], &st);
+ if (!status) {
+ printf("File '%s' exists. Use --force to overwrite.\n",
+ filename[idx]);
+ printf("Process aborted.\n");
+ ret = EEXIST;
+ goto unpack_images_free;
+ }
+ }
+ }
+
+ printf("Unpacking images...\n");
+
+ /* Write the images to files */
+ num_img = 0;
+ for (idx = 0; idx < file_info_count; idx++) {
+ file_info = &files[idx];
+ if (file_info->image_buffer == NULL) {
+ continue;
+ }
+ /* Unpack the image to a file */
+ stream = fopen(filename[idx], "w");
+ if (!stream) {
+ printf("ERROR: cannot open '%s' for writing\n",
+ filename[idx]);
+ ret = EIO;
+ goto unpack_images_free;
+ }
+ bytes_written = fwrite(file_info->image_buffer, sizeof(uint8_t),
+ file_info->size, stream);
+ fclose(stream);
+
+ if (bytes_written != file_info->size) {
+ printf("ERROR: Incorrect write for file \"%s\": Size=%u,"
+ "Written=%lu bytes.\n", filename[idx], file_info->size,
+ bytes_written);
+ ret = EIO;
+ goto unpack_images_free;
+ }
+ num_img++;
+ }
+
+ printf("Done. %u images unpacked\n", num_img);
+
+unpack_images_free:
+ for (idx = 0; idx < file_info_count; idx++) {
+ free(filename[idx]);
+ }
+
+ return ret;
+}
+
+
static void dump_toc(void)
{
unsigned int index = 0;
@@ -528,7 +642,7 @@ static char *get_filename(int argc, char **argv, struct option *options)
*/
optind = 1;
while (1) {
- c = getopt_long(argc, argv, "", options, NULL);
+ c = getopt_long(argc, argv, OPT_STR, options, NULL);
if (c == -1)
break;
@@ -549,19 +663,17 @@ static char *get_filename(int argc, char **argv, struct option *options)
/* Work through command-line options */
-static int parse_cmdline(int argc, char **argv, struct option *options,
- int *do_pack)
+static int parse_cmdline(int argc, char **argv, struct option *options)
{
int c;
int status = 0;
int option_index = 0;
entry_lookup_list_t *lookup_entry;
- int do_dump = 0;
/* restart parse to process all options. starts at 1. */
optind = 1;
while (1) {
- c = getopt_long(argc, argv, "", options, &option_index);
+ c = getopt_long(argc, argv, OPT_STR, options, &option_index);
if (c == -1)
break;
@@ -578,7 +690,7 @@ static int parse_cmdline(int argc, char **argv, struct option *options,
return status;
} else {
/* Update package */
- *do_pack = 1;
+ do_pack = 1;
}
}
}
@@ -586,24 +698,26 @@ static int parse_cmdline(int argc, char **argv, struct option *options,
case OPT_DUMP:
do_dump = 1;
- continue;
+ break;
case OPT_HELP:
print_usage();
exit(0);
+ case OPT_UNPACK:
+ do_unpack = 1;
+ break;
+
+ case OPT_FORCE:
+ do_force = 1;
+ break;
+
default:
/* Unrecognised options are caught in get_filename() */
break;
}
}
-
- /* Do not dump toc if we have an error as it could hide the error */
- if ((status == 0) && (do_dump)) {
- dump_toc();
- }
-
return status;
}
@@ -613,17 +727,17 @@ int main(int argc, char **argv)
int i;
int status;
char *fip_filename;
- int do_pack = 0;
+ struct stat st;
/* Clear file list table. */
memset(files, 0, sizeof(files));
/* Initialise for getopt_long().
* Use image table as defined at top of file to get options.
- * Add 'dump' option, 'help' option and end marker.
+ * Add common options and end marker.
*/
static struct option long_options[(sizeof(toc_entry_lookup_list)/
- sizeof(entry_lookup_list_t)) + 2];
+ sizeof(entry_lookup_list_t)) + 4];
for (i = 0;
/* -1 because we dont want to process end marker in toc table */
@@ -648,6 +762,18 @@ int main(int argc, char **argv)
long_options[i].flag = 0;
long_options[i].val = OPT_HELP;
+ /* Add '--unpack' option */
+ long_options[++i].name = "unpack";
+ long_options[i].has_arg = 0;
+ long_options[i].flag = 0;
+ long_options[i].val = OPT_UNPACK;
+
+ /* Add '--force' option */
+ long_options[++i].name = "force";
+ long_options[i].has_arg = 0;
+ long_options[i].flag = 0;
+ long_options[i].val = OPT_FORCE;
+
/* Zero the last entry (required) */
long_options[++i].name = 0;
long_options[i].has_arg = 0;
@@ -677,7 +803,7 @@ int main(int argc, char **argv)
}
/* Work through provided program arguments and perform actions */
- status = parse_cmdline(argc, argv, long_options, &do_pack);
+ status = parse_cmdline(argc, argv, long_options);
if (status != 0) {
return status;
};
@@ -688,10 +814,28 @@ int main(int argc, char **argv)
return 0;
}
- /* Processed all command line options. Create/update the package if
- * required.
- */
- if (do_pack) {
+ /* Unpack images from FIP always takes precedence over packaging. In
+ * the future, there will be different commands for each action and
+ * only one will be specified in the command line */
+ if (do_unpack) {
+ status = stat(fip_filename, &st);
+ if (status != 0) {
+ printf("ERROR: cannot open %s\n", fip_filename);
+ return status;
+ }
+ /* Warning if user has specified images */
+ if (do_pack) {
+ printf("WARNING: Unpack option specified. Input images "
+ "will be ignored.\n");
+ }
+ status = unpack_images();
+ if (status != 0) {
+ printf("ERROR: failed to unpack package (status = %d).\n",
+ status);
+ return status;
+ }
+ } else if (do_pack) {
+ /* Create/update FIP */
status = pack_images(fip_filename);
if (status != 0) {
printf("Failed to create package (status = %d).\n",
@@ -699,5 +843,10 @@ int main(int argc, char **argv)
}
}
+ /* Do not dump toc if we have an error as it could hide the error */
+ if ((status == 0) && (do_dump)) {
+ dump_toc();
+ }
+
return status;
}