From 40866aaf1c60b31d46b1b969598e3403a4d8a6c1 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 25 Dec 2016 12:41:41 +0900 Subject: [PATCH 01/10] fiptool: fix existence check of FIP input file for update command This line should check the existence of the input file, but it is actually checking the output file. When -o option is given to the "update" command, the outfile is unlikely to exist, then parse_fip() is skipped and an empty FIP file is output. This is wrong behavior. Signed-off-by: Masahiro Yamada --- tools/fiptool/fiptool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index 6145e26d4b..d51d6ab96c 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -882,7 +882,7 @@ static int update_cmd(int argc, char *argv[]) if (outfile[0] == '\0') snprintf(outfile, sizeof(outfile), "%s", argv[0]); - if (access(outfile, F_OK) == 0) + if (access(argv[0], F_OK) == 0) parse_fip(argv[0], &toc_header); if (pflag) From 67973fb4f73411e08f0de39fed0ca21f97de73eb Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 15 Jan 2017 23:20:00 +0900 Subject: [PATCH 02/10] fiptool: remove always true conditional The conditional if (desc != NULL) ... is always true here because we assert it 6 lines above: assert(desc != NULL); Remove the if-conditional and concatenate the printf() calls. Signed-off-by: Masahiro Yamada --- tools/fiptool/fiptool.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index d51d6ab96c..46b8726794 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -554,12 +554,10 @@ static int info_cmd(int argc, char *argv[]) assert(desc != NULL); printf("%s: ", desc->name); image_size = image->size; - printf("offset=0x%llX, size=0x%llX", - (unsigned long long)image_offset, - (unsigned long long)image_size); - if (desc != NULL) - printf(", cmdline=\"--%s\"", - desc->cmdline_name); + printf("offset=0x%llX, size=0x%llX, cmdline=\"--%s\"", + (unsigned long long)image_offset, + (unsigned long long)image_size, + desc->cmdline_name); if (verbose) { unsigned char md[SHA256_DIGEST_LENGTH]; From ea39d557aefe6d8bbd9b08901f2b6f2122e417fe Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 27 Jan 2017 11:57:54 +0900 Subject: [PATCH 03/10] fiptool: revive replace_image() to keep the image order by update command Commit e0f083a09b29 ("fiptool: Prepare ground for expanding the set of images at runtime") introduced another side effect; the "update" command now changes the image order in the FIP. Let's say you have an FIP with BL2, BL31, BL32, BL33. If you update for example, BL32 with the "update" command, you will get a new FIP with BL2, BL31, BL33, BL32, in this order. It happens like this; remove_image() removes the old image from the linked list, add_image() adds the new image at the tail of the list, then images are packed in the new order. Prior to that commit, images were updated by replace_image(), but it was deleted by the re-work. Revive replace_image() that is re-implemented to work with the linked list. Signed-off-by: Masahiro Yamada --- tools/fiptool/fiptool.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index 46b8726794..b79c0d6979 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -254,6 +254,22 @@ static void add_image(image_t *image) nr_images++; } +static void replace_image(image_t *image) +{ + image_t **p = &image_head; + + while (*p) { + if (!memcmp(&(*p)->uuid, &image->uuid, sizeof(image->uuid))) + break; + p = &(*p)->next; + } + + assert(*p != NULL); + + image->next = (*p)->next; + *p = image; +} + static void free_image(image_t *image) { free(image->buffer); @@ -673,8 +689,7 @@ static void update_fip(void) desc->cmdline_name, desc->action_arg); } - remove_image(old_image); - add_image(new_image); + replace_image(new_image); } else { if (verbose) log_dbgx("Adding image %s", From e9e0d2877fb27b81c6b55b57fad684e3f15c15bf Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 27 Jan 2017 12:53:13 +0900 Subject: [PATCH 04/10] fiptool: simplify assert() for add_image(_desc) lookup_image(_desc)_from_uuid() traverses the linked list, so it is not efficient. We just want to make sure *p points to NULL here. Signed-off-by: Masahiro Yamada --- tools/fiptool/fiptool.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index b79c0d6979..7a5c2cd723 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -202,11 +202,10 @@ static void add_image_desc(image_desc_t *desc) { image_desc_t **p = &image_desc_head; - assert(lookup_image_desc_from_uuid(&desc->uuid) == NULL); - while (*p) p = &(*p)->next; + assert(*p == NULL); *p = desc; nr_image_descs++; } @@ -244,11 +243,10 @@ static void add_image(image_t *image) { image_t **p = &image_head; - assert(lookup_image_from_uuid(&image->uuid) == NULL); - while (*p) p = &(*p)->next; + assert(*p == NULL); *p = image; nr_images++; From 9e866d34edded882052c5a9c6dba0885639f3441 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 27 Jan 2017 13:31:40 +0900 Subject: [PATCH 05/10] fiptool: refactor remove_image() We need not handle the image_head as a special case. Just use a double-pointer to simplify the traverse. Signed-off-by: Masahiro Yamada --- tools/fiptool/fiptool.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index 7a5c2cd723..fef1ea8323 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -276,20 +276,20 @@ static void free_image(image_t *image) static void remove_image(image_t *image) { - image_t *tmp = image_head, *prev; + image_t *tmp, **p = &image_head; - if (tmp == image) { - image_head = tmp->next; - free_image(tmp); - } else { - while (tmp != NULL && tmp != image) { - prev = tmp; - tmp = tmp->next; - } - assert(tmp != NULL); - prev->next = tmp->next; - free_image(tmp); + while (*p) { + if (*p == image) + break; + p = &(*p)->next; } + + assert(*p != NULL); + + tmp = *p; + *p = tmp->next; + free_image(tmp); + nr_images--; } From ee07932080e2400d5b0456ae0a200cb849b83bf4 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sat, 14 Jan 2017 11:04:36 +0900 Subject: [PATCH 06/10] fiptool: simplify the top line of command usage We need not mention like [--force], [--out ] because they are included in [opts]. Signed-off-by: Masahiro Yamada --- tools/fiptool/fiptool.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index fef1ea8323..a15e827e6d 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -802,8 +802,9 @@ static void create_usage(void) { toc_entry_t *toc_entry = toc_entries; - printf("fiptool create [--blob uuid=...,file=...] " - "[--plat-toc-flags ] [opts] FIP_FILENAME\n"); + printf("fiptool create [opts] FIP_FILENAME\n"); + printf("\n"); + printf("Options:\n"); printf(" --blob uuid=...,file=...\tAdd an image with the given UUID " "pointed to by file.\n"); printf(" --plat-toc-flags \t16-bit platform specific flag field " @@ -911,8 +912,9 @@ static void update_usage(void) { toc_entry_t *toc_entry = toc_entries; - printf("fiptool update [--blob uuid=...,file=...] [--out FIP_FILENAME] " - "[--plat-toc-flags ] [opts] FIP_FILENAME\n"); + printf("fiptool update [opts] FIP_FILENAME\n"); + printf("\n"); + printf("Options:\n"); printf(" --blob uuid=...,file=...\tAdd or update an image " "with the given UUID pointed to by file.\n"); printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n"); @@ -1048,8 +1050,9 @@ static void unpack_usage(void) { toc_entry_t *toc_entry = toc_entries; - printf("fiptool unpack [--blob uuid=...,file=...] [--force] " - "[--out ] [opts] FIP_FILENAME\n"); + printf("fiptool unpack [opts] FIP_FILENAME\n"); + printf("\n"); + printf("Options:\n"); printf(" --blob uuid=...,file=...\tUnpack an image with the given UUID " "to file.\n"); printf(" --force\t\t\tIf the output file already exists, use --force to " @@ -1171,8 +1174,9 @@ static void remove_usage(void) { toc_entry_t *toc_entry = toc_entries; - printf("fiptool remove [--blob uuid=...] [--force] " - "[--out FIP_FILENAME] [opts] FIP_FILENAME\n"); + printf("fiptool remove [opts] FIP_FILENAME\n"); + printf("\n"); + printf("Options:\n"); printf(" --blob uuid=...\tRemove an image with the given UUID.\n"); printf(" --force\t\tIf the output FIP file already exists, use --force to " "overwrite it.\n"); From 4f96a498436d63864de38b29ff2496755e16fb0c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 13 Jan 2017 02:13:06 +0900 Subject: [PATCH 07/10] fiptool: fix the global option in usage The global option --verbose should come after the "fiptool". Signed-off-by: Masahiro Yamada --- tools/fiptool/fiptool.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index a15e827e6d..0040018bbb 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -1226,7 +1226,7 @@ static int help_cmd(int argc, char *argv[]) static void usage(void) { - printf("usage: [--verbose] fiptool []\n"); + printf("usage: fiptool [--verbose] []\n"); printf("Global options supported:\n"); printf(" --verbose\tEnable verbose output for all commands.\n"); fputc('\n', stderr); From a1da83f5fc91b15761fa418aedf14e155a7e24c6 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 27 Jan 2017 03:54:02 +0900 Subject: [PATCH 08/10] fiptool: add xfwrite() helper We have same patterns for fwrite(). Signed-off-by: Masahiro Yamada --- tools/fiptool/fiptool.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index 0040018bbb..b02635f671 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -160,6 +160,12 @@ static void *xzalloc(size_t size, const char *msg) return memset(xmalloc(size, msg), 0, size); } +static void xfwrite(void *buf, size_t size, FILE *fp, const char *filename) +{ + if (fwrite(buf, 1, size, fp) != size) + log_errx("Failed to write %s", filename); +} + static image_desc_t *new_image_desc(const uuid_t *uuid, const char *name, const char *cmdline_name) { @@ -497,8 +503,7 @@ static int write_image_to_file(const image_t *image, const char *filename) fp = fopen(filename, "w"); if (fp == NULL) log_err("fopen"); - if (fwrite(image->buffer, 1, image->size, fp) != image->size) - log_errx("Failed to write %s", filename); + xfwrite(image->buffer, image->size, fp, filename); fclose(fp); return 0; } @@ -645,16 +650,14 @@ static int pack_images(const char *filename, uint64_t toc_flags) if (verbose) log_dbgx("Metadata size: %zu bytes", buf_size); - if (fwrite(buf, 1, buf_size, fp) != buf_size) - log_errx("Failed to write image to %s", filename); + xfwrite(buf, buf_size, fp, filename); free(buf); if (verbose) log_dbgx("Payload size: %zu bytes", payload_size); for (image = image_head; image != NULL; image = image->next) - if (fwrite(image->buffer, 1, image->size, fp) != image->size) - log_errx("Failed to write image to %s", filename); + xfwrite(image->buffer, image->size, fp, filename); fclose(fp); return 0; From 65caa3d0ad72eb22c5e0a2a98aaa159e51eab43b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 27 Jan 2017 03:56:58 +0900 Subject: [PATCH 09/10] fiptool: embed fip_toc_entry in struct image The struct image has "uuid" and "size" to memorize the field values they had in the TOC entry. So, parse_fip() copies them from struct fip_toc_entry to struct image, then pack_images() copies them back to struct fip_toc_entry. The next commit (support --align option) will require to save the "offset" field as well. This makes me realize that struct image can embed struct fip_toc_entry. This commit will allow the "flags" field to persevere the "update" command. At this moment, the "flags" is not used in a useful way. (Yet, platforms can save their own parameters in the flags field.) It makes sense to save it unless users explicitly replace the image. Signed-off-by: Masahiro Yamada --- tools/fiptool/fiptool.c | 62 +++++++++++++++-------------------------- tools/fiptool/fiptool.h | 8 +++--- 2 files changed, 27 insertions(+), 43 deletions(-) diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index b02635f671..6288cbfd4e 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -263,7 +263,8 @@ static void replace_image(image_t *image) image_t **p = &image_head; while (*p) { - if (!memcmp(&(*p)->uuid, &image->uuid, sizeof(image->uuid))) + if (!memcmp(&(*p)->toc_e.uuid, &image->toc_e.uuid, + sizeof(image->toc_e.uuid))) break; p = &(*p)->next; } @@ -337,7 +338,7 @@ static image_t *lookup_image_from_uuid(const uuid_t *uuid) image_t *image; for (image = image_head; image != NULL; image = image->next) - if (memcmp(&image->uuid, uuid, sizeof(uuid_t)) == 0) + if (!memcmp(&image->toc_e.uuid, uuid, sizeof(*uuid))) return image; return NULL; } @@ -430,7 +431,7 @@ static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out) */ image = xzalloc(sizeof(*image), "failed to allocate memory for image"); - memcpy(&image->uuid, &toc_entry->uuid, sizeof(uuid_t)); + image->toc_e = *toc_entry; image->buffer = xmalloc(toc_entry->size, "failed to allocate image buffer, is FIP file corrupted?"); /* Overflow checks before memory copy. */ @@ -441,17 +442,16 @@ static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out) memcpy(image->buffer, buf + toc_entry->offset_address, toc_entry->size); - image->size = toc_entry->size; /* If this is an unknown image, create a descriptor for it. */ - desc = lookup_image_desc_from_uuid(&image->uuid); + desc = lookup_image_desc_from_uuid(&toc_entry->uuid); if (desc == NULL) { char name[_UUID_STR_LEN + 1], filename[PATH_MAX]; - uuid_to_str(name, sizeof(name), &image->uuid); + uuid_to_str(name, sizeof(name), &toc_entry->uuid); snprintf(filename, sizeof(filename), "%s%s", name, ".bin"); - desc = new_image_desc(&image->uuid, name, "blob"); + desc = new_image_desc(&toc_entry->uuid, name, "blob"); desc->action = DO_UNPACK; desc->action_arg = xstrdup(filename, "failed to allocate memory for blob filename"); @@ -486,11 +486,11 @@ static image_t *read_image_from_file(const uuid_t *uuid, const char *filename) log_errx("fstat %s", filename); image = xzalloc(sizeof(*image), "failed to allocate memory for image"); - memcpy(&image->uuid, uuid, sizeof(uuid_t)); + image->toc_e.uuid = *uuid; image->buffer = xmalloc(st.st_size, "failed to allocate image buffer"); if (fread(image->buffer, 1, st.st_size, fp) != st.st_size) log_errx("Failed to read %s", filename); - image->size = st.st_size; + image->toc_e.size = st.st_size; fclose(fp); return image; @@ -503,7 +503,7 @@ static int write_image_to_file(const image_t *image, const char *filename) fp = fopen(filename, "w"); if (fp == NULL) log_err("fopen"); - xfwrite(image->buffer, image->size, fp, filename); + xfwrite(image->buffer, image->toc_e.size, fp, filename); fclose(fp); return 0; } @@ -544,8 +544,6 @@ static void md_print(const unsigned char *md, size_t len) static int info_cmd(int argc, char *argv[]) { image_t *image; - uint64_t image_offset; - uint64_t image_size; fip_toc_header_t toc_header; if (argc != 2) @@ -563,29 +561,24 @@ static int info_cmd(int argc, char *argv[]) (unsigned long long)toc_header.flags); } - image_offset = sizeof(fip_toc_header_t) + - (sizeof(fip_toc_entry_t) * (nr_images + 1)); - for (image = image_head; image != NULL; image = image->next) { image_desc_t *desc; - desc = lookup_image_desc_from_uuid(&image->uuid); + desc = lookup_image_desc_from_uuid(&image->toc_e.uuid); assert(desc != NULL); - printf("%s: ", desc->name); - image_size = image->size; - printf("offset=0x%llX, size=0x%llX, cmdline=\"--%s\"", - (unsigned long long)image_offset, - (unsigned long long)image_size, + printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"--%s\"", + desc->name, + (unsigned long long)image->toc_e.offset_address, + (unsigned long long)image->toc_e.size, desc->cmdline_name); if (verbose) { unsigned char md[SHA256_DIGEST_LENGTH]; - SHA256(image->buffer, image_size, md); + SHA256(image->buffer, image->toc_e.size, md); printf(", sha256="); md_print(md, sizeof(md)); } putchar('\n'); - image_offset += image_size; } free_images(); @@ -605,12 +598,7 @@ static int pack_images(const char *filename, uint64_t toc_flags) fip_toc_header_t *toc_header; fip_toc_entry_t *toc_entry; char *buf; - uint64_t entry_offset, buf_size, payload_size; - - /* Calculate total payload size and allocate scratch buffer. */ - payload_size = 0; - for (image = image_head; image != NULL; image = image->next) - payload_size += image->size; + uint64_t entry_offset, buf_size, payload_size = 0; buf_size = sizeof(fip_toc_header_t) + sizeof(fip_toc_entry_t) * (nr_images + 1); @@ -628,19 +616,15 @@ static int pack_images(const char *filename, uint64_t toc_flags) entry_offset = buf_size; for (image = image_head; image != NULL; image = image->next) { - memcpy(&toc_entry->uuid, &image->uuid, sizeof(uuid_t)); - toc_entry->offset_address = entry_offset; - toc_entry->size = image->size; - toc_entry->flags = 0; - entry_offset += toc_entry->size; - toc_entry++; + payload_size += image->toc_e.size; + image->toc_e.offset_address = entry_offset; + *toc_entry++ = image->toc_e; + entry_offset += image->toc_e.size; } /* Append a null uuid entry to mark the end of ToC entries. */ - memcpy(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)); + memset(toc_entry, 0, sizeof(*toc_entry)); toc_entry->offset_address = entry_offset; - toc_entry->size = 0; - toc_entry->flags = 0; /* Generate the FIP file. */ fp = fopen(filename, "w"); @@ -657,7 +641,7 @@ static int pack_images(const char *filename, uint64_t toc_flags) log_dbgx("Payload size: %zu bytes", payload_size); for (image = image_head; image != NULL; image = image->next) - xfwrite(image->buffer, image->size, fp, filename); + xfwrite(image->buffer, image->toc_e.size, fp, filename); fclose(fp); return 0; diff --git a/tools/fiptool/fiptool.h b/tools/fiptool/fiptool.h index 6ace400d29..be0c6f0da3 100644 --- a/tools/fiptool/fiptool.h +++ b/tools/fiptool/fiptool.h @@ -34,6 +34,7 @@ #include #include +#include "firmware_image_package.h" #include "uuid.h" #define NELEM(x) (sizeof (x) / sizeof *(x)) @@ -61,10 +62,9 @@ typedef struct image_desc { } image_desc_t; typedef struct image { - uuid_t uuid; - size_t size; - void *buffer; - struct image *next; + struct fip_toc_entry toc_e; + void *buffer; + struct image *next; } image_t; typedef struct cmd { From 1c75d5dfb03181bc481fe021dc5a8ab29c0f7557 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Sun, 25 Dec 2016 13:52:22 +0900 Subject: [PATCH 10/10] fiptool: support --align option to add desired alignment to image offset The current fiptool packs all the images without any padding between them. So, the offset to each image has no alignment. This is not efficient, for example, when the FIP is read from a block-oriented device. For example, (e)MMC is accessed by block-addressing. The block size is 512 byte. So, the best case is each image is aligned by 512 byte since the DMA engine can transfer the whole of the image to its load address directly. The worst case is the offset does not have even DMA-capable alignment (this is where we stand now). In this case, we need to transfer every block to a bounce buffer, then do memcpy() from the bounce buffer to our final destination. At least, this should work with the abstraction by the block I/O layer, but the CPU-intervention for the whole data transfer makes it really slow. This commit adds a new option --align to the fiptool. This option, if given, requests the tool to align each component in the FIP file by the specified byte. Also, add a new Make option FIP_ALIGN for easier access to this feature; users can give something like FIP_ALIGN=512 from the command line, or add "FIP_ALIGN := 512" to their platform.mk file. Signed-off-by: Masahiro Yamada --- Makefile | 4 ++++ make_helpers/defaults.mk | 3 +++ tools/fiptool/fiptool.c | 52 ++++++++++++++++++++++++++++++++++++---- 3 files changed, 54 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index e9a07840ed..001e94b8c4 100644 --- a/Makefile +++ b/Makefile @@ -350,6 +350,10 @@ ifeq (${ENABLE_PSCI_STAT},1) ENABLE_PMF := 1 endif +ifneq (${FIP_ALIGN},0) +FIP_ARGS += --align ${FIP_ALIGN} +endif + ################################################################################ # Auxiliary tools (fiptool, cert_create, etc) ################################################################################ diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index fc39819d71..0b93dfcaca 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -89,6 +89,9 @@ ENABLE_RUNTIME_INSTRUMENTATION := 0 # Build flag to treat usage of deprecated platform and framework APIs as error. ERROR_DEPRECATED := 0 +# Byte alignment that each component in FIP is aligned to +FIP_ALIGN := 0 + # Default FIP file name FIP_NAME := fip.bin diff --git a/tools/fiptool/fiptool.c b/tools/fiptool/fiptool.c index 6288cbfd4e..865aeae1d9 100644 --- a/tools/fiptool/fiptool.c +++ b/tools/fiptool/fiptool.c @@ -50,6 +50,7 @@ #define OPT_TOC_ENTRY 0 #define OPT_PLAT_TOC_FLAGS 1 +#define OPT_ALIGN 2 static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid); static image_t *lookup_image_from_uuid(const uuid_t *uuid); @@ -591,7 +592,7 @@ static void info_usage(void) exit(1); } -static int pack_images(const char *filename, uint64_t toc_flags) +static int pack_images(const char *filename, uint64_t toc_flags, unsigned long align) { FILE *fp; image_t *image; @@ -617,6 +618,7 @@ static int pack_images(const char *filename, uint64_t toc_flags) entry_offset = buf_size; for (image = image_head; image != NULL; image = image->next) { payload_size += image->toc_e.size; + entry_offset = (entry_offset + align - 1) & ~(align - 1); image->toc_e.offset_address = entry_offset; *toc_entry++ = image->toc_e; entry_offset += image->toc_e.size; @@ -640,8 +642,12 @@ static int pack_images(const char *filename, uint64_t toc_flags) if (verbose) log_dbgx("Payload size: %zu bytes", payload_size); - for (image = image_head; image != NULL; image = image->next) + for (image = image_head; image != NULL; image = image->next) { + if (fseek(fp, image->toc_e.offset_address, SEEK_SET)) + log_errx("Failed to set file position"); + xfwrite(image->buffer, image->toc_e.size, fp, filename); + } fclose(fp); return 0; @@ -697,6 +703,24 @@ static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags) *toc_flags |= flags << 32; } +static int is_power_of_2(unsigned long x) +{ + return x && !(x & (x - 1)); +} + +static unsigned long get_image_align(char *arg) +{ + char *endptr; + unsigned long align; + + errno = 0; + align = strtoul(arg, &endptr, 10); + if (*endptr != '\0' || !is_power_of_2(align) || errno != 0) + log_errx("Invalid alignment: %s", arg); + + return align; +} + static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len) { char *p; @@ -717,6 +741,7 @@ static int create_cmd(int argc, char *argv[]) struct option *opts = NULL; size_t nr_opts = 0; unsigned long long toc_flags = 0; + unsigned long align = 1; if (argc < 2) create_usage(); @@ -724,6 +749,7 @@ static int create_cmd(int argc, char *argv[]) opts = fill_common_opts(opts, &nr_opts, required_argument); opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument, OPT_PLAT_TOC_FLAGS); + opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN); opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); opts = add_opt(opts, &nr_opts, NULL, 0, 0); @@ -745,6 +771,9 @@ static int create_cmd(int argc, char *argv[]) case OPT_PLAT_TOC_FLAGS: parse_plat_toc_flags(optarg, &toc_flags); break; + case OPT_ALIGN: + align = get_image_align(optarg); + break; case 'b': { char name[_UUID_STR_LEN + 1]; char filename[PATH_MAX] = { 0 }; @@ -780,7 +809,7 @@ static int create_cmd(int argc, char *argv[]) update_fip(); - pack_images(argv[0], toc_flags); + pack_images(argv[0], toc_flags, align); free_images(); return 0; } @@ -792,6 +821,7 @@ static void create_usage(void) printf("fiptool create [opts] FIP_FILENAME\n"); printf("\n"); printf("Options:\n"); + printf(" --align \t\tEach image is aligned to (default: 1).\n"); printf(" --blob uuid=...,file=...\tAdd an image with the given UUID " "pointed to by file.\n"); printf(" --plat-toc-flags \t16-bit platform specific flag field " @@ -811,12 +841,14 @@ static int update_cmd(int argc, char *argv[]) char outfile[PATH_MAX] = { 0 }; fip_toc_header_t toc_header = { 0 }; unsigned long long toc_flags = 0; + unsigned long align = 1; int pflag = 0; if (argc < 2) update_usage(); opts = fill_common_opts(opts, &nr_opts, required_argument); + opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN); opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); opts = add_opt(opts, &nr_opts, "out", required_argument, 'o'); opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument, @@ -864,6 +896,9 @@ static int update_cmd(int argc, char *argv[]) set_image_desc_action(desc, DO_PACK, filename); break; } + case OPT_ALIGN: + align = get_image_align(optarg); + break; case 'o': snprintf(outfile, sizeof(outfile), "%s", optarg); break; @@ -890,7 +925,7 @@ static int update_cmd(int argc, char *argv[]) update_fip(); - pack_images(outfile, toc_flags); + pack_images(outfile, toc_flags, align); free_images(); return 0; } @@ -902,6 +937,7 @@ static void update_usage(void) printf("fiptool update [opts] FIP_FILENAME\n"); printf("\n"); printf("Options:\n"); + printf(" --align \t\tEach image is aligned to (default: 1).\n"); printf(" --blob uuid=...,file=...\tAdd or update an image " "with the given UUID pointed to by file.\n"); printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n"); @@ -1062,12 +1098,14 @@ static int remove_cmd(int argc, char *argv[]) char outfile[PATH_MAX] = { 0 }; fip_toc_header_t toc_header; image_desc_t *desc; + unsigned long align = 1; int fflag = 0; if (argc < 2) remove_usage(); opts = fill_common_opts(opts, &nr_opts, no_argument); + opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN); opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); opts = add_opt(opts, &nr_opts, "force", no_argument, 'f'); opts = add_opt(opts, &nr_opts, "out", required_argument, 'o'); @@ -1088,6 +1126,9 @@ static int remove_cmd(int argc, char *argv[]) set_image_desc_action(desc, DO_REMOVE, NULL); break; } + case OPT_ALIGN: + align = get_image_align(optarg); + break; case 'b': { char name[_UUID_STR_LEN + 1], filename[PATH_MAX]; uuid_t uuid = { 0 }; @@ -1152,7 +1193,7 @@ static int remove_cmd(int argc, char *argv[]) } } - pack_images(outfile, toc_header.flags); + pack_images(outfile, toc_header.flags, align); free_images(); return 0; } @@ -1164,6 +1205,7 @@ static void remove_usage(void) printf("fiptool remove [opts] FIP_FILENAME\n"); printf("\n"); printf("Options:\n"); + printf(" --align \tEach image is aligned to (default: 1).\n"); printf(" --blob uuid=...\tRemove an image with the given UUID.\n"); printf(" --force\t\tIf the output FIP file already exists, use --force to " "overwrite it.\n");