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 <yamada.masahiro@socionext.com>
This commit is contained in:
Masahiro Yamada 2016-12-25 13:52:22 +09:00
parent 65caa3d0ad
commit 1c75d5dfb0
3 changed files with 54 additions and 5 deletions

View File

@ -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)
################################################################################

View File

@ -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

View File

@ -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 <value>\t\tEach image is aligned to <value> (default: 1).\n");
printf(" --blob uuid=...,file=...\tAdd an image with the given UUID "
"pointed to by file.\n");
printf(" --plat-toc-flags <value>\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 <value>\t\tEach image is aligned to <value> (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 <value>\tEach image is aligned to <value> (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");