fiptool: Add support for operating on binary blobs using the UUID

Previously, fiptool only understood a fixed set of images as
specified in tbbr_config.c.  It preserved unknown images during
the update, unpack and remove operations but it was not possible to
explicitly refer to one of those unknown images.

Add a new --blob option to create/update/unpack/remove images that
are not known at compile time.  This is accomplished by specifying
the UUID and filename pair as shown below:

$ ./fiptool create --blob uuid=01234567-89ab-cdef-0123-456789abcdef,file=foo.bin fip.bin
$ ./fiptool info fip.bin
01234567-89ab-cdef-0123-456789abcdef: offset=0x60, size=0x1AA68

Fixes ARM-software/tf-issues#420

Change-Id: Iaac2504b9a4252289c09e73d29645cbe240f3a82
Signed-off-by: dp-arm <dimitris.papastamos@arm.com>
This commit is contained in:
dp-arm 2016-11-03 13:59:26 +00:00
parent e0f083a09b
commit fcab6bbe39
2 changed files with 225 additions and 24 deletions

View File

@ -37,6 +37,9 @@
/* Length of a node address (an IEEE 802 address). */
#define _UUID_NODE_LEN 6
/* Length of UUID string including dashes. */
#define _UUID_STR_LEN 36
/*
* See also:
* http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt

View File

@ -293,6 +293,42 @@ static image_t *lookup_image_from_uuid(const uuid_t *uuid)
return NULL;
}
static void uuid_to_str(char *s, size_t len, const uuid_t *u)
{
assert(len >= (_UUID_STR_LEN + 1));
snprintf(s, len, "%08X-%04X-%04X-%04X-%04X%04X%04X",
u->time_low,
u->time_mid,
u->time_hi_and_version,
((uint16_t)u->clock_seq_hi_and_reserved << 8) | u->clock_seq_low,
((uint16_t)u->node[0] << 8) | u->node[1],
((uint16_t)u->node[2] << 8) | u->node[3],
((uint16_t)u->node[4] << 8) | u->node[5]);
}
static void uuid_from_str(uuid_t *u, const char *s)
{
int n;
if (s == NULL)
log_errx("UUID cannot be NULL");
if (strlen(s) != _UUID_STR_LEN)
log_errx("Invalid UUID: %s", s);
n = sscanf(s,
"%8x-%4hx-%4hx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
&u->time_low, &u->time_mid, &u->time_hi_and_version,
&u->clock_seq_hi_and_reserved, &u->clock_seq_low, &u->node[0],
&u->node[1], &u->node[2], &u->node[3], &u->node[4], &u->node[5]);
/*
* Given the format specifier above, we expect 11 items to be scanned
* for a properly formatted UUID.
*/
if (n != 11)
log_errx("Invalid UUID: %s", s);
}
static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
{
struct stat st;
@ -300,7 +336,6 @@ static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
char *buf, *bufend;
fip_toc_header_t *toc_header;
fip_toc_entry_t *toc_entry;
image_t *image;
int terminated = 0;
fp = fopen(filename, "r");
@ -331,6 +366,9 @@ static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
/* Walk through each ToC entry in the file. */
while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) {
image_t *image;
image_desc_t *desc;
/* Found the ToC terminator, we are done. */
if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) {
terminated = 1;
@ -356,6 +394,21 @@ static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out)
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);
if (desc == NULL) {
char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
uuid_to_str(name, sizeof(name), &image->uuid);
snprintf(filename, sizeof(filename), "%s%s",
name, ".bin");
desc = new_image_desc(&image->uuid, name, "blob");
desc->action = DO_UNPACK;
desc->action_arg = xstrdup(filename,
"failed to allocate memory for blob filename");
add_image_desc(desc);
}
add_image(image);
toc_entry++;
@ -444,7 +497,7 @@ static int info_cmd(int argc, char *argv[])
{
image_t *image;
uint64_t image_offset;
uint64_t image_size = 0;
uint64_t image_size;
fip_toc_header_t toc_header;
if (argc != 2)
@ -469,10 +522,8 @@ static int info_cmd(int argc, char *argv[])
image_desc_t *desc;
desc = lookup_image_desc_from_uuid(&image->uuid);
if (desc != NULL)
printf("%s: ", desc->name);
else
printf("Unknown entry: ");
assert(desc != NULL);
printf("%s: ", desc->name);
image_size = image->size;
printf("offset=0x%llX, size=0x%llX",
(unsigned long long)image_offset,
@ -578,10 +629,11 @@ static int pack_images(const char *filename, uint64_t toc_flags)
static void update_fip(void)
{
image_desc_t *desc;
image_t *new_image, *old_image;
/* Add or replace images in the FIP file. */
for (desc = image_desc_head; desc != NULL; desc = desc->next) {
image_t *new_image, *old_image;
if (desc->action != DO_PACK)
continue;
@ -590,7 +642,7 @@ static void update_fip(void)
old_image = lookup_image_from_uuid(&desc->uuid);
if (old_image != NULL) {
if (verbose) {
log_dbgx("Replacing image %s.bin with %s",
log_dbgx("Replacing %s with %s",
desc->cmdline_name,
desc->action_arg);
}
@ -618,6 +670,21 @@ static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags)
*toc_flags |= flags << 32;
}
static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len)
{
char *p;
for (p = strtok(arg, ","); p != NULL; p = strtok(NULL, ",")) {
if (strncmp(p, "uuid=", strlen("uuid=")) == 0) {
p += strlen("uuid=");
uuid_from_str(uuid, p);
} else if (strncmp(p, "file=", strlen("file=")) == 0) {
p += strlen("file=");
snprintf(filename, len, "%s", p);
}
}
}
static int create_cmd(int argc, char *argv[])
{
struct option *opts = NULL;
@ -630,12 +697,13 @@ 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, "blob", required_argument, 'b');
opts = add_opt(opts, &nr_opts, NULL, 0, 0);
while (1) {
int c, opt_index = 0;
c = getopt_long(argc, argv, "", opts, &opt_index);
c = getopt_long(argc, argv, "b:", opts, &opt_index);
if (c == -1)
break;
@ -655,6 +723,36 @@ static int create_cmd(int argc, char *argv[])
case OPT_PLAT_TOC_FLAGS:
parse_plat_toc_flags(optarg, &toc_flags);
break;
case 'b': {
char name[_UUID_STR_LEN + 1];
char filename[PATH_MAX] = { 0 };
uuid_t uuid = { 0 };
image_desc_t *desc;
parse_blob_opt(optarg, &uuid,
filename, sizeof(filename));
if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
filename[0] == '\0')
create_usage();
desc = lookup_image_desc_from_uuid(&uuid);
if (desc != NULL) {
if (desc->action != DO_UNSPEC)
free(desc->action_arg);
desc->action = DO_PACK;
desc->action_arg = xstrdup(filename,
"failed to allocate memory for argument");
} else {
uuid_to_str(name, sizeof(name), &uuid);
desc = new_image_desc(&uuid, name, "blob");
desc->action = DO_PACK;
desc->action_arg = xstrdup(filename,
"failed to allocate memory for argument");
add_image_desc(desc);
}
break;
}
default:
create_usage();
}
@ -677,7 +775,10 @@ static void create_usage(void)
{
toc_entry_t *toc_entry = toc_entries;
printf("fiptool create [--plat-toc-flags <value>] [opts] FIP_FILENAME\n");
printf("fiptool create [--blob uuid=...,file=...] "
"[--plat-toc-flags <value>] [opts] FIP_FILENAME\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 "
"occupying bits 32-47 in 64-bit ToC header.\n");
fputc('\n', stderr);
@ -692,7 +793,7 @@ static int update_cmd(int argc, char *argv[])
{
struct option *opts = NULL;
size_t nr_opts = 0;
char outfile[FILENAME_MAX] = { 0 };
char outfile[PATH_MAX] = { 0 };
fip_toc_header_t toc_header = { 0 };
unsigned long long toc_flags = 0;
int pflag = 0;
@ -701,6 +802,7 @@ static int update_cmd(int argc, char *argv[])
update_usage();
opts = fill_common_opts(opts, &nr_opts, required_argument);
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,
OPT_PLAT_TOC_FLAGS);
@ -709,7 +811,7 @@ static int update_cmd(int argc, char *argv[])
while (1) {
int c, opt_index = 0;
c = getopt_long(argc, argv, "o:", opts, &opt_index);
c = getopt_long(argc, argv, "b:o:", opts, &opt_index);
if (c == -1)
break;
@ -730,6 +832,36 @@ static int update_cmd(int argc, char *argv[])
parse_plat_toc_flags(optarg, &toc_flags);
pflag = 1;
break;
case 'b': {
char name[_UUID_STR_LEN + 1];
char filename[PATH_MAX] = { 0 };
uuid_t uuid = { 0 };
image_desc_t *desc;
parse_blob_opt(optarg, &uuid,
filename, sizeof(filename));
if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
filename[0] == '\0')
update_usage();
desc = lookup_image_desc_from_uuid(&uuid);
if (desc != NULL) {
if (desc->action != DO_UNSPEC)
free(desc->action_arg);
desc->action = DO_PACK;
desc->action_arg = xstrdup(filename,
"failed to allocate memory for argument");
} else {
uuid_to_str(name, sizeof(name), &uuid);
desc = new_image_desc(&uuid, name, "blob");
desc->action = DO_PACK;
desc->action_arg = xstrdup(filename,
"failed to allocate memory for argument");
add_image_desc(desc);
}
break;
}
case 'o':
snprintf(outfile, sizeof(outfile), "%s", optarg);
break;
@ -765,8 +897,10 @@ static void update_usage(void)
{
toc_entry_t *toc_entry = toc_entries;
printf("fiptool update [--out FIP_FILENAME] "
printf("fiptool update [--blob uuid=...,file=...] [--out FIP_FILENAME] "
"[--plat-toc-flags <value>] [opts] FIP_FILENAME\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");
printf(" --plat-toc-flags <value>\t16-bit platform specific flag field "
"occupying bits 32-47 in 64-bit ToC header.\n");
@ -782,7 +916,7 @@ static int unpack_cmd(int argc, char *argv[])
{
struct option *opts = NULL;
size_t nr_opts = 0;
char file[FILENAME_MAX], outdir[PATH_MAX] = { 0 };
char outdir[PATH_MAX] = { 0 };
image_desc_t *desc;
int fflag = 0;
int unpack_all = 1;
@ -791,6 +925,7 @@ static int unpack_cmd(int argc, char *argv[])
unpack_usage();
opts = fill_common_opts(opts, &nr_opts, required_argument);
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');
opts = add_opt(opts, &nr_opts, NULL, 0, 0);
@ -798,7 +933,7 @@ static int unpack_cmd(int argc, char *argv[])
while (1) {
int c, opt_index = 0;
c = getopt_long(argc, argv, "fo:", opts, &opt_index);
c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
if (c == -1)
break;
@ -816,6 +951,37 @@ static int unpack_cmd(int argc, char *argv[])
unpack_all = 0;
break;
}
case 'b': {
char name[_UUID_STR_LEN + 1];
char filename[PATH_MAX] = { 0 };
uuid_t uuid = { 0 };
image_desc_t *desc;
parse_blob_opt(optarg, &uuid,
filename, sizeof(filename));
if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 ||
filename[0] == '\0')
unpack_usage();
desc = lookup_image_desc_from_uuid(&uuid);
if (desc != NULL) {
if (desc->action != DO_UNSPEC)
free(desc->action_arg);
desc->action = DO_UNPACK;
desc->action_arg = xstrdup(filename,
"failed to allocate memory for argument");
} else {
uuid_to_str(name, sizeof(name), &uuid);
desc = new_image_desc(&uuid, name, "blob");
desc->action = DO_UNPACK;
desc->action_arg = xstrdup(filename,
"failed to allocate memory for argument");
add_image_desc(desc);
}
unpack_all = 0;
break;
}
case 'f':
fflag = 1;
break;
@ -841,6 +1007,7 @@ static int unpack_cmd(int argc, char *argv[])
/* Unpack all specified images. */
for (desc = image_desc_head; desc != NULL; desc = desc->next) {
char file[PATH_MAX];
image_t *image;
if (!unpack_all && desc->action != DO_UNPACK)
@ -857,7 +1024,7 @@ static int unpack_cmd(int argc, char *argv[])
image = lookup_image_from_uuid(&desc->uuid);
if (image == NULL) {
if (!unpack_all)
log_warnx("Requested image %s is not in %s",
log_warnx("%s does not exist in %s",
file, argv[0]);
continue;
}
@ -880,10 +1047,13 @@ static void unpack_usage(void)
{
toc_entry_t *toc_entry = toc_entries;
printf("fiptool unpack [--force] [--out <path>] [opts] FIP_FILENAME\n");
printf(" --force\tIf the output file already exists, use --force to "
printf("fiptool unpack [--blob uuid=...,file=...] [--force] "
"[--out <path>] [opts] FIP_FILENAME\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 "
"overwrite it.\n");
printf(" --out path\tSet the output directory path.\n");
printf(" --out path\t\t\tSet the output directory path.\n");
fputc('\n', stderr);
printf("Specific images are unpacked with the following options:\n");
for (; toc_entry->cmdline_name != NULL; toc_entry++)
@ -898,7 +1068,7 @@ static int remove_cmd(int argc, char *argv[])
{
struct option *opts = NULL;
size_t nr_opts = 0;
char outfile[FILENAME_MAX] = { 0 };
char outfile[PATH_MAX] = { 0 };
fip_toc_header_t toc_header;
image_desc_t *desc;
int fflag = 0;
@ -907,6 +1077,7 @@ static int remove_cmd(int argc, char *argv[])
remove_usage();
opts = fill_common_opts(opts, &nr_opts, no_argument);
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');
opts = add_opt(opts, &nr_opts, NULL, 0, 0);
@ -914,7 +1085,7 @@ static int remove_cmd(int argc, char *argv[])
while (1) {
int c, opt_index = 0;
c = getopt_long(argc, argv, "fo:", opts, &opt_index);
c = getopt_long(argc, argv, "b:fo:", opts, &opt_index);
if (c == -1)
break;
@ -928,6 +1099,30 @@ static int remove_cmd(int argc, char *argv[])
desc->action_arg = NULL;
break;
}
case 'b': {
char name[_UUID_STR_LEN + 1], filename[PATH_MAX];
uuid_t uuid = { 0 };
image_desc_t *desc;
parse_blob_opt(optarg, &uuid,
filename, sizeof(filename));
if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0)
remove_usage();
desc = lookup_image_desc_from_uuid(&uuid);
if (desc != NULL) {
desc->action = DO_REMOVE;
desc->action_arg = NULL;
} else {
uuid_to_str(name, sizeof(name), &uuid);
desc = new_image_desc(&uuid, name, "blob");
desc->action = DO_REMOVE;
desc->action_arg = NULL;
add_image_desc(desc);
}
break;
}
case 'f':
fflag = 1;
break;
@ -959,14 +1154,15 @@ static int remove_cmd(int argc, char *argv[])
if (desc->action != DO_REMOVE)
continue;
image = lookup_image_from_uuid(&desc->uuid);
if (image != NULL) {
if (verbose)
log_dbgx("Removing %s.bin",
log_dbgx("Removing %s",
desc->cmdline_name);
remove_image(image);
} else {
log_warnx("Requested image %s.bin is not in %s",
log_warnx("%s does not exist in %s",
desc->cmdline_name, argv[0]);
}
}
@ -980,7 +1176,9 @@ static void remove_usage(void)
{
toc_entry_t *toc_entry = toc_entries;
printf("fiptool remove [--force] [--out FIP_FILENAME] [opts] FIP_FILENAME\n");
printf("fiptool remove [--blob uuid=...] [--force] "
"[--out FIP_FILENAME] [opts] FIP_FILENAME\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");
printf(" --out FIP_FILENAME\tSet an alternative output FIP file.\n");