1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2016-2023, ARM Limited and Contributors. All rights reserved. 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #ifndef _MSC_VER 8*91f16700Schasinglulu #include <sys/mount.h> 9*91f16700Schasinglulu #endif 10*91f16700Schasinglulu #include <sys/types.h> 11*91f16700Schasinglulu #include <sys/stat.h> 12*91f16700Schasinglulu 13*91f16700Schasinglulu #include <assert.h> 14*91f16700Schasinglulu #include <errno.h> 15*91f16700Schasinglulu #include <limits.h> 16*91f16700Schasinglulu #include <stdarg.h> 17*91f16700Schasinglulu #include <stdint.h> 18*91f16700Schasinglulu #include <stdio.h> 19*91f16700Schasinglulu #include <stdlib.h> 20*91f16700Schasinglulu #include <string.h> 21*91f16700Schasinglulu 22*91f16700Schasinglulu #include "fiptool.h" 23*91f16700Schasinglulu #include "tbbr_config.h" 24*91f16700Schasinglulu 25*91f16700Schasinglulu #define OPT_TOC_ENTRY 0 26*91f16700Schasinglulu #define OPT_PLAT_TOC_FLAGS 1 27*91f16700Schasinglulu #define OPT_ALIGN 2 28*91f16700Schasinglulu 29*91f16700Schasinglulu static int info_cmd(int argc, char *argv[]); 30*91f16700Schasinglulu static void info_usage(int); 31*91f16700Schasinglulu static int create_cmd(int argc, char *argv[]); 32*91f16700Schasinglulu static void create_usage(int); 33*91f16700Schasinglulu static int update_cmd(int argc, char *argv[]); 34*91f16700Schasinglulu static void update_usage(int); 35*91f16700Schasinglulu static int unpack_cmd(int argc, char *argv[]); 36*91f16700Schasinglulu static void unpack_usage(int); 37*91f16700Schasinglulu static int remove_cmd(int argc, char *argv[]); 38*91f16700Schasinglulu static void remove_usage(int); 39*91f16700Schasinglulu static int version_cmd(int argc, char *argv[]); 40*91f16700Schasinglulu static void version_usage(int); 41*91f16700Schasinglulu static int help_cmd(int argc, char *argv[]); 42*91f16700Schasinglulu static void usage(void); 43*91f16700Schasinglulu 44*91f16700Schasinglulu /* Available subcommands. */ 45*91f16700Schasinglulu static cmd_t cmds[] = { 46*91f16700Schasinglulu { .name = "info", .handler = info_cmd, .usage = info_usage }, 47*91f16700Schasinglulu { .name = "create", .handler = create_cmd, .usage = create_usage }, 48*91f16700Schasinglulu { .name = "update", .handler = update_cmd, .usage = update_usage }, 49*91f16700Schasinglulu { .name = "unpack", .handler = unpack_cmd, .usage = unpack_usage }, 50*91f16700Schasinglulu { .name = "remove", .handler = remove_cmd, .usage = remove_usage }, 51*91f16700Schasinglulu { .name = "version", .handler = version_cmd, .usage = version_usage }, 52*91f16700Schasinglulu { .name = "help", .handler = help_cmd, .usage = NULL }, 53*91f16700Schasinglulu }; 54*91f16700Schasinglulu 55*91f16700Schasinglulu static image_desc_t *image_desc_head; 56*91f16700Schasinglulu static size_t nr_image_descs; 57*91f16700Schasinglulu static const uuid_t uuid_null; 58*91f16700Schasinglulu static int verbose; 59*91f16700Schasinglulu 60*91f16700Schasinglulu static void vlog(int prio, const char *msg, va_list ap) 61*91f16700Schasinglulu { 62*91f16700Schasinglulu char *prefix[] = { "DEBUG", "WARN", "ERROR" }; 63*91f16700Schasinglulu 64*91f16700Schasinglulu fprintf(stderr, "%s: ", prefix[prio]); 65*91f16700Schasinglulu vfprintf(stderr, msg, ap); 66*91f16700Schasinglulu fputc('\n', stderr); 67*91f16700Schasinglulu } 68*91f16700Schasinglulu 69*91f16700Schasinglulu static void log_dbgx(const char *msg, ...) 70*91f16700Schasinglulu { 71*91f16700Schasinglulu va_list ap; 72*91f16700Schasinglulu 73*91f16700Schasinglulu va_start(ap, msg); 74*91f16700Schasinglulu vlog(LOG_DBG, msg, ap); 75*91f16700Schasinglulu va_end(ap); 76*91f16700Schasinglulu } 77*91f16700Schasinglulu 78*91f16700Schasinglulu static void log_warnx(const char *msg, ...) 79*91f16700Schasinglulu { 80*91f16700Schasinglulu va_list ap; 81*91f16700Schasinglulu 82*91f16700Schasinglulu va_start(ap, msg); 83*91f16700Schasinglulu vlog(LOG_WARN, msg, ap); 84*91f16700Schasinglulu va_end(ap); 85*91f16700Schasinglulu } 86*91f16700Schasinglulu 87*91f16700Schasinglulu static void log_err(const char *msg, ...) 88*91f16700Schasinglulu { 89*91f16700Schasinglulu char buf[512]; 90*91f16700Schasinglulu va_list ap; 91*91f16700Schasinglulu 92*91f16700Schasinglulu va_start(ap, msg); 93*91f16700Schasinglulu snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno)); 94*91f16700Schasinglulu vlog(LOG_ERR, buf, ap); 95*91f16700Schasinglulu va_end(ap); 96*91f16700Schasinglulu exit(1); 97*91f16700Schasinglulu } 98*91f16700Schasinglulu 99*91f16700Schasinglulu static void log_errx(const char *msg, ...) 100*91f16700Schasinglulu { 101*91f16700Schasinglulu va_list ap; 102*91f16700Schasinglulu 103*91f16700Schasinglulu va_start(ap, msg); 104*91f16700Schasinglulu vlog(LOG_ERR, msg, ap); 105*91f16700Schasinglulu va_end(ap); 106*91f16700Schasinglulu exit(1); 107*91f16700Schasinglulu } 108*91f16700Schasinglulu 109*91f16700Schasinglulu static char *xstrdup(const char *s, const char *msg) 110*91f16700Schasinglulu { 111*91f16700Schasinglulu char *d; 112*91f16700Schasinglulu 113*91f16700Schasinglulu d = strdup(s); 114*91f16700Schasinglulu if (d == NULL) 115*91f16700Schasinglulu log_errx("strdup: %s", msg); 116*91f16700Schasinglulu return d; 117*91f16700Schasinglulu } 118*91f16700Schasinglulu 119*91f16700Schasinglulu static void *xmalloc(size_t size, const char *msg) 120*91f16700Schasinglulu { 121*91f16700Schasinglulu void *d; 122*91f16700Schasinglulu 123*91f16700Schasinglulu d = malloc(size); 124*91f16700Schasinglulu if (d == NULL) 125*91f16700Schasinglulu log_errx("malloc: %s", msg); 126*91f16700Schasinglulu return d; 127*91f16700Schasinglulu } 128*91f16700Schasinglulu 129*91f16700Schasinglulu static void *xzalloc(size_t size, const char *msg) 130*91f16700Schasinglulu { 131*91f16700Schasinglulu return memset(xmalloc(size, msg), 0, size); 132*91f16700Schasinglulu } 133*91f16700Schasinglulu 134*91f16700Schasinglulu static void xfwrite(void *buf, size_t size, FILE *fp, const char *filename) 135*91f16700Schasinglulu { 136*91f16700Schasinglulu if (fwrite(buf, 1, size, fp) != size) 137*91f16700Schasinglulu log_errx("Failed to write %s", filename); 138*91f16700Schasinglulu } 139*91f16700Schasinglulu 140*91f16700Schasinglulu static image_desc_t *new_image_desc(const uuid_t *uuid, 141*91f16700Schasinglulu const char *name, const char *cmdline_name) 142*91f16700Schasinglulu { 143*91f16700Schasinglulu image_desc_t *desc; 144*91f16700Schasinglulu 145*91f16700Schasinglulu desc = xzalloc(sizeof(*desc), 146*91f16700Schasinglulu "failed to allocate memory for image descriptor"); 147*91f16700Schasinglulu memcpy(&desc->uuid, uuid, sizeof(uuid_t)); 148*91f16700Schasinglulu desc->name = xstrdup(name, 149*91f16700Schasinglulu "failed to allocate memory for image name"); 150*91f16700Schasinglulu desc->cmdline_name = xstrdup(cmdline_name, 151*91f16700Schasinglulu "failed to allocate memory for image command line name"); 152*91f16700Schasinglulu desc->action = DO_UNSPEC; 153*91f16700Schasinglulu return desc; 154*91f16700Schasinglulu } 155*91f16700Schasinglulu 156*91f16700Schasinglulu static void set_image_desc_action(image_desc_t *desc, int action, 157*91f16700Schasinglulu const char *arg) 158*91f16700Schasinglulu { 159*91f16700Schasinglulu assert(desc != NULL); 160*91f16700Schasinglulu 161*91f16700Schasinglulu if (desc->action_arg != (char *)DO_UNSPEC) 162*91f16700Schasinglulu free(desc->action_arg); 163*91f16700Schasinglulu desc->action = action; 164*91f16700Schasinglulu desc->action_arg = NULL; 165*91f16700Schasinglulu if (arg != NULL) 166*91f16700Schasinglulu desc->action_arg = xstrdup(arg, 167*91f16700Schasinglulu "failed to allocate memory for argument"); 168*91f16700Schasinglulu } 169*91f16700Schasinglulu 170*91f16700Schasinglulu static void free_image_desc(image_desc_t *desc) 171*91f16700Schasinglulu { 172*91f16700Schasinglulu free(desc->name); 173*91f16700Schasinglulu free(desc->cmdline_name); 174*91f16700Schasinglulu free(desc->action_arg); 175*91f16700Schasinglulu if (desc->image) { 176*91f16700Schasinglulu free(desc->image->buffer); 177*91f16700Schasinglulu free(desc->image); 178*91f16700Schasinglulu } 179*91f16700Schasinglulu free(desc); 180*91f16700Schasinglulu } 181*91f16700Schasinglulu 182*91f16700Schasinglulu static void add_image_desc(image_desc_t *desc) 183*91f16700Schasinglulu { 184*91f16700Schasinglulu image_desc_t **p = &image_desc_head; 185*91f16700Schasinglulu 186*91f16700Schasinglulu while (*p) 187*91f16700Schasinglulu p = &(*p)->next; 188*91f16700Schasinglulu 189*91f16700Schasinglulu assert(*p == NULL); 190*91f16700Schasinglulu *p = desc; 191*91f16700Schasinglulu nr_image_descs++; 192*91f16700Schasinglulu } 193*91f16700Schasinglulu 194*91f16700Schasinglulu static void free_image_descs(void) 195*91f16700Schasinglulu { 196*91f16700Schasinglulu image_desc_t *desc = image_desc_head, *tmp; 197*91f16700Schasinglulu 198*91f16700Schasinglulu while (desc != NULL) { 199*91f16700Schasinglulu tmp = desc->next; 200*91f16700Schasinglulu free_image_desc(desc); 201*91f16700Schasinglulu desc = tmp; 202*91f16700Schasinglulu nr_image_descs--; 203*91f16700Schasinglulu } 204*91f16700Schasinglulu assert(nr_image_descs == 0); 205*91f16700Schasinglulu } 206*91f16700Schasinglulu 207*91f16700Schasinglulu static void fill_image_descs(void) 208*91f16700Schasinglulu { 209*91f16700Schasinglulu toc_entry_t *toc_entry; 210*91f16700Schasinglulu 211*91f16700Schasinglulu for (toc_entry = toc_entries; 212*91f16700Schasinglulu toc_entry->cmdline_name != NULL; 213*91f16700Schasinglulu toc_entry++) { 214*91f16700Schasinglulu image_desc_t *desc; 215*91f16700Schasinglulu 216*91f16700Schasinglulu desc = new_image_desc(&toc_entry->uuid, 217*91f16700Schasinglulu toc_entry->name, 218*91f16700Schasinglulu toc_entry->cmdline_name); 219*91f16700Schasinglulu add_image_desc(desc); 220*91f16700Schasinglulu } 221*91f16700Schasinglulu #ifdef PLAT_DEF_FIP_UUID 222*91f16700Schasinglulu for (toc_entry = plat_def_toc_entries; 223*91f16700Schasinglulu toc_entry->cmdline_name != NULL; 224*91f16700Schasinglulu toc_entry++) { 225*91f16700Schasinglulu image_desc_t *desc; 226*91f16700Schasinglulu 227*91f16700Schasinglulu desc = new_image_desc(&toc_entry->uuid, 228*91f16700Schasinglulu toc_entry->name, 229*91f16700Schasinglulu toc_entry->cmdline_name); 230*91f16700Schasinglulu add_image_desc(desc); 231*91f16700Schasinglulu } 232*91f16700Schasinglulu #endif 233*91f16700Schasinglulu } 234*91f16700Schasinglulu 235*91f16700Schasinglulu static image_desc_t *lookup_image_desc_from_uuid(const uuid_t *uuid) 236*91f16700Schasinglulu { 237*91f16700Schasinglulu image_desc_t *desc; 238*91f16700Schasinglulu 239*91f16700Schasinglulu for (desc = image_desc_head; desc != NULL; desc = desc->next) 240*91f16700Schasinglulu if (memcmp(&desc->uuid, uuid, sizeof(uuid_t)) == 0) 241*91f16700Schasinglulu return desc; 242*91f16700Schasinglulu return NULL; 243*91f16700Schasinglulu } 244*91f16700Schasinglulu 245*91f16700Schasinglulu static image_desc_t *lookup_image_desc_from_opt(const char *opt) 246*91f16700Schasinglulu { 247*91f16700Schasinglulu image_desc_t *desc; 248*91f16700Schasinglulu 249*91f16700Schasinglulu for (desc = image_desc_head; desc != NULL; desc = desc->next) 250*91f16700Schasinglulu if (strcmp(desc->cmdline_name, opt) == 0) 251*91f16700Schasinglulu return desc; 252*91f16700Schasinglulu return NULL; 253*91f16700Schasinglulu } 254*91f16700Schasinglulu 255*91f16700Schasinglulu static void uuid_to_str(char *s, size_t len, const uuid_t *u) 256*91f16700Schasinglulu { 257*91f16700Schasinglulu assert(len >= (_UUID_STR_LEN + 1)); 258*91f16700Schasinglulu 259*91f16700Schasinglulu snprintf(s, len, 260*91f16700Schasinglulu "%02X%02X%02X%02X-%02X%02X-%02X%02X-%04X-%04X%04X%04X", 261*91f16700Schasinglulu u->time_low[0], u->time_low[1], u->time_low[2], u->time_low[3], 262*91f16700Schasinglulu u->time_mid[0], u->time_mid[1], 263*91f16700Schasinglulu u->time_hi_and_version[0], u->time_hi_and_version[1], 264*91f16700Schasinglulu (u->clock_seq_hi_and_reserved << 8) | u->clock_seq_low, 265*91f16700Schasinglulu (u->node[0] << 8) | u->node[1], 266*91f16700Schasinglulu (u->node[2] << 8) | u->node[3], 267*91f16700Schasinglulu (u->node[4] << 8) | u->node[5]); 268*91f16700Schasinglulu } 269*91f16700Schasinglulu 270*91f16700Schasinglulu static void uuid_from_str(uuid_t *u, const char *s) 271*91f16700Schasinglulu { 272*91f16700Schasinglulu int n; 273*91f16700Schasinglulu 274*91f16700Schasinglulu if (s == NULL) 275*91f16700Schasinglulu log_errx("UUID cannot be NULL"); 276*91f16700Schasinglulu if (strlen(s) != _UUID_STR_LEN) 277*91f16700Schasinglulu log_errx("Invalid UUID: %s", s); 278*91f16700Schasinglulu 279*91f16700Schasinglulu n = sscanf(s, 280*91f16700Schasinglulu "%2hhx%2hhx%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx-%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx", 281*91f16700Schasinglulu &u->time_low[0], &u->time_low[1], &u->time_low[2], &u->time_low[3], 282*91f16700Schasinglulu &u->time_mid[0], &u->time_mid[1], 283*91f16700Schasinglulu &u->time_hi_and_version[0], &u->time_hi_and_version[1], 284*91f16700Schasinglulu &u->clock_seq_hi_and_reserved, &u->clock_seq_low, 285*91f16700Schasinglulu &u->node[0], &u->node[1], 286*91f16700Schasinglulu &u->node[2], &u->node[3], 287*91f16700Schasinglulu &u->node[4], &u->node[5]); 288*91f16700Schasinglulu /* 289*91f16700Schasinglulu * Given the format specifier above, we expect 16 items to be scanned 290*91f16700Schasinglulu * for a properly formatted UUID. 291*91f16700Schasinglulu */ 292*91f16700Schasinglulu if (n != 16) 293*91f16700Schasinglulu log_errx("Invalid UUID: %s", s); 294*91f16700Schasinglulu } 295*91f16700Schasinglulu 296*91f16700Schasinglulu static int parse_fip(const char *filename, fip_toc_header_t *toc_header_out) 297*91f16700Schasinglulu { 298*91f16700Schasinglulu struct BLD_PLAT_STAT st; 299*91f16700Schasinglulu FILE *fp; 300*91f16700Schasinglulu char *buf, *bufend; 301*91f16700Schasinglulu fip_toc_header_t *toc_header; 302*91f16700Schasinglulu fip_toc_entry_t *toc_entry; 303*91f16700Schasinglulu int terminated = 0; 304*91f16700Schasinglulu size_t st_size; 305*91f16700Schasinglulu 306*91f16700Schasinglulu fp = fopen(filename, "rb"); 307*91f16700Schasinglulu if (fp == NULL) 308*91f16700Schasinglulu log_err("fopen %s", filename); 309*91f16700Schasinglulu 310*91f16700Schasinglulu if (fstat(fileno(fp), &st) == -1) 311*91f16700Schasinglulu log_err("fstat %s", filename); 312*91f16700Schasinglulu 313*91f16700Schasinglulu st_size = st.st_size; 314*91f16700Schasinglulu 315*91f16700Schasinglulu #ifdef BLKGETSIZE64 316*91f16700Schasinglulu if ((st.st_mode & S_IFBLK) != 0) 317*91f16700Schasinglulu if (ioctl(fileno(fp), BLKGETSIZE64, &st_size) == -1) 318*91f16700Schasinglulu log_err("ioctl %s", filename); 319*91f16700Schasinglulu #endif 320*91f16700Schasinglulu 321*91f16700Schasinglulu buf = xmalloc(st_size, "failed to load file into memory"); 322*91f16700Schasinglulu if (fread(buf, 1, st_size, fp) != st_size) 323*91f16700Schasinglulu log_errx("Failed to read %s", filename); 324*91f16700Schasinglulu bufend = buf + st_size; 325*91f16700Schasinglulu fclose(fp); 326*91f16700Schasinglulu 327*91f16700Schasinglulu if (st_size < sizeof(fip_toc_header_t)) 328*91f16700Schasinglulu log_errx("FIP %s is truncated", filename); 329*91f16700Schasinglulu 330*91f16700Schasinglulu toc_header = (fip_toc_header_t *)buf; 331*91f16700Schasinglulu toc_entry = (fip_toc_entry_t *)(toc_header + 1); 332*91f16700Schasinglulu 333*91f16700Schasinglulu if (toc_header->name != TOC_HEADER_NAME) 334*91f16700Schasinglulu log_errx("%s is not a FIP file", filename); 335*91f16700Schasinglulu 336*91f16700Schasinglulu /* Return the ToC header if the caller wants it. */ 337*91f16700Schasinglulu if (toc_header_out != NULL) 338*91f16700Schasinglulu *toc_header_out = *toc_header; 339*91f16700Schasinglulu 340*91f16700Schasinglulu /* Walk through each ToC entry in the file. */ 341*91f16700Schasinglulu while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) { 342*91f16700Schasinglulu image_t *image; 343*91f16700Schasinglulu image_desc_t *desc; 344*91f16700Schasinglulu 345*91f16700Schasinglulu /* Found the ToC terminator, we are done. */ 346*91f16700Schasinglulu if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) { 347*91f16700Schasinglulu terminated = 1; 348*91f16700Schasinglulu break; 349*91f16700Schasinglulu } 350*91f16700Schasinglulu 351*91f16700Schasinglulu /* 352*91f16700Schasinglulu * Build a new image out of the ToC entry and add it to the 353*91f16700Schasinglulu * table of images. 354*91f16700Schasinglulu */ 355*91f16700Schasinglulu image = xzalloc(sizeof(*image), 356*91f16700Schasinglulu "failed to allocate memory for image"); 357*91f16700Schasinglulu image->toc_e = *toc_entry; 358*91f16700Schasinglulu image->buffer = xmalloc(toc_entry->size, 359*91f16700Schasinglulu "failed to allocate image buffer, is FIP file corrupted?"); 360*91f16700Schasinglulu /* Overflow checks before memory copy. */ 361*91f16700Schasinglulu if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address) 362*91f16700Schasinglulu log_errx("FIP %s is corrupted: entry size exceeds 64 bit address space", 363*91f16700Schasinglulu filename); 364*91f16700Schasinglulu if (toc_entry->size + toc_entry->offset_address > st_size) 365*91f16700Schasinglulu log_errx("FIP %s is corrupted: entry size exceeds FIP file size", 366*91f16700Schasinglulu filename); 367*91f16700Schasinglulu 368*91f16700Schasinglulu memcpy(image->buffer, buf + toc_entry->offset_address, 369*91f16700Schasinglulu toc_entry->size); 370*91f16700Schasinglulu 371*91f16700Schasinglulu /* If this is an unknown image, create a descriptor for it. */ 372*91f16700Schasinglulu desc = lookup_image_desc_from_uuid(&toc_entry->uuid); 373*91f16700Schasinglulu if (desc == NULL) { 374*91f16700Schasinglulu char name[_UUID_STR_LEN + 1], filename[PATH_MAX]; 375*91f16700Schasinglulu 376*91f16700Schasinglulu uuid_to_str(name, sizeof(name), &toc_entry->uuid); 377*91f16700Schasinglulu snprintf(filename, sizeof(filename), "%s%s", 378*91f16700Schasinglulu name, ".bin"); 379*91f16700Schasinglulu desc = new_image_desc(&toc_entry->uuid, name, "blob"); 380*91f16700Schasinglulu desc->action = DO_UNPACK; 381*91f16700Schasinglulu desc->action_arg = xstrdup(filename, 382*91f16700Schasinglulu "failed to allocate memory for blob filename"); 383*91f16700Schasinglulu add_image_desc(desc); 384*91f16700Schasinglulu } 385*91f16700Schasinglulu 386*91f16700Schasinglulu assert(desc->image == NULL); 387*91f16700Schasinglulu desc->image = image; 388*91f16700Schasinglulu 389*91f16700Schasinglulu toc_entry++; 390*91f16700Schasinglulu } 391*91f16700Schasinglulu 392*91f16700Schasinglulu if (terminated == 0) 393*91f16700Schasinglulu log_errx("FIP %s does not have a ToC terminator entry", 394*91f16700Schasinglulu filename); 395*91f16700Schasinglulu free(buf); 396*91f16700Schasinglulu return 0; 397*91f16700Schasinglulu } 398*91f16700Schasinglulu 399*91f16700Schasinglulu static image_t *read_image_from_file(const uuid_t *uuid, const char *filename) 400*91f16700Schasinglulu { 401*91f16700Schasinglulu struct BLD_PLAT_STAT st; 402*91f16700Schasinglulu image_t *image; 403*91f16700Schasinglulu FILE *fp; 404*91f16700Schasinglulu 405*91f16700Schasinglulu assert(uuid != NULL); 406*91f16700Schasinglulu assert(filename != NULL); 407*91f16700Schasinglulu 408*91f16700Schasinglulu fp = fopen(filename, "rb"); 409*91f16700Schasinglulu if (fp == NULL) 410*91f16700Schasinglulu log_err("fopen %s", filename); 411*91f16700Schasinglulu 412*91f16700Schasinglulu if (fstat(fileno(fp), &st) == -1) 413*91f16700Schasinglulu log_errx("fstat %s", filename); 414*91f16700Schasinglulu 415*91f16700Schasinglulu image = xzalloc(sizeof(*image), "failed to allocate memory for image"); 416*91f16700Schasinglulu image->toc_e.uuid = *uuid; 417*91f16700Schasinglulu image->buffer = xmalloc(st.st_size, "failed to allocate image buffer"); 418*91f16700Schasinglulu if (fread(image->buffer, 1, st.st_size, fp) != st.st_size) 419*91f16700Schasinglulu log_errx("Failed to read %s", filename); 420*91f16700Schasinglulu image->toc_e.size = st.st_size; 421*91f16700Schasinglulu 422*91f16700Schasinglulu fclose(fp); 423*91f16700Schasinglulu return image; 424*91f16700Schasinglulu } 425*91f16700Schasinglulu 426*91f16700Schasinglulu static int write_image_to_file(const image_t *image, const char *filename) 427*91f16700Schasinglulu { 428*91f16700Schasinglulu FILE *fp; 429*91f16700Schasinglulu 430*91f16700Schasinglulu fp = fopen(filename, "wb"); 431*91f16700Schasinglulu if (fp == NULL) 432*91f16700Schasinglulu log_err("fopen"); 433*91f16700Schasinglulu xfwrite(image->buffer, image->toc_e.size, fp, filename); 434*91f16700Schasinglulu fclose(fp); 435*91f16700Schasinglulu return 0; 436*91f16700Schasinglulu } 437*91f16700Schasinglulu 438*91f16700Schasinglulu static struct option *add_opt(struct option *opts, size_t *nr_opts, 439*91f16700Schasinglulu const char *name, int has_arg, int val) 440*91f16700Schasinglulu { 441*91f16700Schasinglulu opts = realloc(opts, (*nr_opts + 1) * sizeof(*opts)); 442*91f16700Schasinglulu if (opts == NULL) 443*91f16700Schasinglulu log_err("realloc"); 444*91f16700Schasinglulu opts[*nr_opts].name = name; 445*91f16700Schasinglulu opts[*nr_opts].has_arg = has_arg; 446*91f16700Schasinglulu opts[*nr_opts].flag = NULL; 447*91f16700Schasinglulu opts[*nr_opts].val = val; 448*91f16700Schasinglulu ++*nr_opts; 449*91f16700Schasinglulu return opts; 450*91f16700Schasinglulu } 451*91f16700Schasinglulu 452*91f16700Schasinglulu static struct option *fill_common_opts(struct option *opts, size_t *nr_opts, 453*91f16700Schasinglulu int has_arg) 454*91f16700Schasinglulu { 455*91f16700Schasinglulu image_desc_t *desc; 456*91f16700Schasinglulu 457*91f16700Schasinglulu for (desc = image_desc_head; desc != NULL; desc = desc->next) 458*91f16700Schasinglulu opts = add_opt(opts, nr_opts, desc->cmdline_name, has_arg, 459*91f16700Schasinglulu OPT_TOC_ENTRY); 460*91f16700Schasinglulu return opts; 461*91f16700Schasinglulu } 462*91f16700Schasinglulu 463*91f16700Schasinglulu #if !STATIC 464*91f16700Schasinglulu static void md_print(const unsigned char *md, size_t len) 465*91f16700Schasinglulu { 466*91f16700Schasinglulu size_t i; 467*91f16700Schasinglulu 468*91f16700Schasinglulu for (i = 0; i < len; i++) 469*91f16700Schasinglulu printf("%02x", md[i]); 470*91f16700Schasinglulu } 471*91f16700Schasinglulu #endif 472*91f16700Schasinglulu 473*91f16700Schasinglulu static int info_cmd(int argc, char *argv[]) 474*91f16700Schasinglulu { 475*91f16700Schasinglulu image_desc_t *desc; 476*91f16700Schasinglulu fip_toc_header_t toc_header; 477*91f16700Schasinglulu 478*91f16700Schasinglulu if (argc != 2) 479*91f16700Schasinglulu info_usage(EXIT_FAILURE); 480*91f16700Schasinglulu argc--, argv++; 481*91f16700Schasinglulu 482*91f16700Schasinglulu parse_fip(argv[0], &toc_header); 483*91f16700Schasinglulu 484*91f16700Schasinglulu if (verbose) { 485*91f16700Schasinglulu log_dbgx("toc_header[name]: 0x%llX", 486*91f16700Schasinglulu (unsigned long long)toc_header.name); 487*91f16700Schasinglulu log_dbgx("toc_header[serial_number]: 0x%llX", 488*91f16700Schasinglulu (unsigned long long)toc_header.serial_number); 489*91f16700Schasinglulu log_dbgx("toc_header[flags]: 0x%llX", 490*91f16700Schasinglulu (unsigned long long)toc_header.flags); 491*91f16700Schasinglulu } 492*91f16700Schasinglulu 493*91f16700Schasinglulu for (desc = image_desc_head; desc != NULL; desc = desc->next) { 494*91f16700Schasinglulu image_t *image = desc->image; 495*91f16700Schasinglulu 496*91f16700Schasinglulu if (image == NULL) 497*91f16700Schasinglulu continue; 498*91f16700Schasinglulu printf("%s: offset=0x%llX, size=0x%llX, cmdline=\"--%s\"", 499*91f16700Schasinglulu desc->name, 500*91f16700Schasinglulu (unsigned long long)image->toc_e.offset_address, 501*91f16700Schasinglulu (unsigned long long)image->toc_e.size, 502*91f16700Schasinglulu desc->cmdline_name); 503*91f16700Schasinglulu 504*91f16700Schasinglulu /* 505*91f16700Schasinglulu * Omit this informative code portion for: 506*91f16700Schasinglulu * Visual Studio missing SHA256. 507*91f16700Schasinglulu * Statically linked builds. 508*91f16700Schasinglulu */ 509*91f16700Schasinglulu #if !defined(_MSC_VER) && !STATIC 510*91f16700Schasinglulu if (verbose) { 511*91f16700Schasinglulu unsigned char md[SHA256_DIGEST_LENGTH]; 512*91f16700Schasinglulu 513*91f16700Schasinglulu SHA256(image->buffer, image->toc_e.size, md); 514*91f16700Schasinglulu printf(", sha256="); 515*91f16700Schasinglulu md_print(md, sizeof(md)); 516*91f16700Schasinglulu } 517*91f16700Schasinglulu #endif 518*91f16700Schasinglulu putchar('\n'); 519*91f16700Schasinglulu } 520*91f16700Schasinglulu 521*91f16700Schasinglulu return 0; 522*91f16700Schasinglulu } 523*91f16700Schasinglulu 524*91f16700Schasinglulu static void info_usage(int exit_status) 525*91f16700Schasinglulu { 526*91f16700Schasinglulu printf("fiptool info FIP_FILENAME\n"); 527*91f16700Schasinglulu exit(exit_status); 528*91f16700Schasinglulu } 529*91f16700Schasinglulu 530*91f16700Schasinglulu static int pack_images(const char *filename, uint64_t toc_flags, unsigned long align) 531*91f16700Schasinglulu { 532*91f16700Schasinglulu FILE *fp; 533*91f16700Schasinglulu image_desc_t *desc; 534*91f16700Schasinglulu fip_toc_header_t *toc_header; 535*91f16700Schasinglulu fip_toc_entry_t *toc_entry; 536*91f16700Schasinglulu char *buf; 537*91f16700Schasinglulu uint64_t entry_offset, buf_size, payload_size = 0, pad_size; 538*91f16700Schasinglulu size_t nr_images = 0; 539*91f16700Schasinglulu 540*91f16700Schasinglulu for (desc = image_desc_head; desc != NULL; desc = desc->next) 541*91f16700Schasinglulu if (desc->image != NULL) 542*91f16700Schasinglulu nr_images++; 543*91f16700Schasinglulu 544*91f16700Schasinglulu buf_size = sizeof(fip_toc_header_t) + 545*91f16700Schasinglulu sizeof(fip_toc_entry_t) * (nr_images + 1); 546*91f16700Schasinglulu buf = calloc(1, buf_size); 547*91f16700Schasinglulu if (buf == NULL) 548*91f16700Schasinglulu log_err("calloc"); 549*91f16700Schasinglulu 550*91f16700Schasinglulu /* Build up header and ToC entries from the image table. */ 551*91f16700Schasinglulu toc_header = (fip_toc_header_t *)buf; 552*91f16700Schasinglulu toc_header->name = TOC_HEADER_NAME; 553*91f16700Schasinglulu toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER; 554*91f16700Schasinglulu toc_header->flags = toc_flags; 555*91f16700Schasinglulu 556*91f16700Schasinglulu toc_entry = (fip_toc_entry_t *)(toc_header + 1); 557*91f16700Schasinglulu 558*91f16700Schasinglulu entry_offset = buf_size; 559*91f16700Schasinglulu for (desc = image_desc_head; desc != NULL; desc = desc->next) { 560*91f16700Schasinglulu image_t *image = desc->image; 561*91f16700Schasinglulu 562*91f16700Schasinglulu if (image == NULL || (image->toc_e.size == 0ULL)) 563*91f16700Schasinglulu continue; 564*91f16700Schasinglulu payload_size += image->toc_e.size; 565*91f16700Schasinglulu entry_offset = (entry_offset + align - 1) & ~(align - 1); 566*91f16700Schasinglulu image->toc_e.offset_address = entry_offset; 567*91f16700Schasinglulu *toc_entry++ = image->toc_e; 568*91f16700Schasinglulu entry_offset += image->toc_e.size; 569*91f16700Schasinglulu } 570*91f16700Schasinglulu 571*91f16700Schasinglulu /* 572*91f16700Schasinglulu * Append a null uuid entry to mark the end of ToC entries. 573*91f16700Schasinglulu * NOTE the offset address for the last toc_entry must match the fip 574*91f16700Schasinglulu * size. 575*91f16700Schasinglulu */ 576*91f16700Schasinglulu memset(toc_entry, 0, sizeof(*toc_entry)); 577*91f16700Schasinglulu toc_entry->offset_address = (entry_offset + align - 1) & ~(align - 1); 578*91f16700Schasinglulu 579*91f16700Schasinglulu /* Generate the FIP file. */ 580*91f16700Schasinglulu fp = fopen(filename, "wb"); 581*91f16700Schasinglulu if (fp == NULL) 582*91f16700Schasinglulu log_err("fopen %s", filename); 583*91f16700Schasinglulu 584*91f16700Schasinglulu if (verbose) 585*91f16700Schasinglulu log_dbgx("Metadata size: %zu bytes", buf_size); 586*91f16700Schasinglulu 587*91f16700Schasinglulu xfwrite(buf, buf_size, fp, filename); 588*91f16700Schasinglulu 589*91f16700Schasinglulu if (verbose) 590*91f16700Schasinglulu log_dbgx("Payload size: %zu bytes", payload_size); 591*91f16700Schasinglulu 592*91f16700Schasinglulu for (desc = image_desc_head; desc != NULL; desc = desc->next) { 593*91f16700Schasinglulu image_t *image = desc->image; 594*91f16700Schasinglulu 595*91f16700Schasinglulu if (image == NULL) 596*91f16700Schasinglulu continue; 597*91f16700Schasinglulu if (fseek(fp, image->toc_e.offset_address, SEEK_SET)) 598*91f16700Schasinglulu log_errx("Failed to set file position"); 599*91f16700Schasinglulu 600*91f16700Schasinglulu xfwrite(image->buffer, image->toc_e.size, fp, filename); 601*91f16700Schasinglulu } 602*91f16700Schasinglulu 603*91f16700Schasinglulu if (fseek(fp, entry_offset, SEEK_SET)) 604*91f16700Schasinglulu log_errx("Failed to set file position"); 605*91f16700Schasinglulu 606*91f16700Schasinglulu pad_size = toc_entry->offset_address - entry_offset; 607*91f16700Schasinglulu while (pad_size--) 608*91f16700Schasinglulu fputc(0x0, fp); 609*91f16700Schasinglulu 610*91f16700Schasinglulu free(buf); 611*91f16700Schasinglulu fclose(fp); 612*91f16700Schasinglulu return 0; 613*91f16700Schasinglulu } 614*91f16700Schasinglulu 615*91f16700Schasinglulu /* 616*91f16700Schasinglulu * This function is shared between the create and update subcommands. 617*91f16700Schasinglulu * The difference between the two subcommands is that when the FIP file 618*91f16700Schasinglulu * is created, the parsing of an existing FIP is skipped. This results 619*91f16700Schasinglulu * in update_fip() creating the new FIP file from scratch because the 620*91f16700Schasinglulu * internal image table is not populated. 621*91f16700Schasinglulu */ 622*91f16700Schasinglulu static void update_fip(void) 623*91f16700Schasinglulu { 624*91f16700Schasinglulu image_desc_t *desc; 625*91f16700Schasinglulu 626*91f16700Schasinglulu /* Add or replace images in the FIP file. */ 627*91f16700Schasinglulu for (desc = image_desc_head; desc != NULL; desc = desc->next) { 628*91f16700Schasinglulu image_t *image; 629*91f16700Schasinglulu 630*91f16700Schasinglulu if (desc->action != DO_PACK) 631*91f16700Schasinglulu continue; 632*91f16700Schasinglulu 633*91f16700Schasinglulu image = read_image_from_file(&desc->uuid, 634*91f16700Schasinglulu desc->action_arg); 635*91f16700Schasinglulu if (desc->image != NULL) { 636*91f16700Schasinglulu if (verbose) { 637*91f16700Schasinglulu log_dbgx("Replacing %s with %s", 638*91f16700Schasinglulu desc->cmdline_name, 639*91f16700Schasinglulu desc->action_arg); 640*91f16700Schasinglulu } 641*91f16700Schasinglulu free(desc->image); 642*91f16700Schasinglulu desc->image = image; 643*91f16700Schasinglulu } else { 644*91f16700Schasinglulu if (verbose) 645*91f16700Schasinglulu log_dbgx("Adding image %s", 646*91f16700Schasinglulu desc->action_arg); 647*91f16700Schasinglulu desc->image = image; 648*91f16700Schasinglulu } 649*91f16700Schasinglulu } 650*91f16700Schasinglulu } 651*91f16700Schasinglulu 652*91f16700Schasinglulu static void parse_plat_toc_flags(const char *arg, unsigned long long *toc_flags) 653*91f16700Schasinglulu { 654*91f16700Schasinglulu unsigned long long flags; 655*91f16700Schasinglulu char *endptr; 656*91f16700Schasinglulu 657*91f16700Schasinglulu errno = 0; 658*91f16700Schasinglulu flags = strtoull(arg, &endptr, 16); 659*91f16700Schasinglulu if (*endptr != '\0' || flags > UINT16_MAX || errno != 0) 660*91f16700Schasinglulu log_errx("Invalid platform ToC flags: %s", arg); 661*91f16700Schasinglulu /* Platform ToC flags is a 16-bit field occupying bits [32-47]. */ 662*91f16700Schasinglulu *toc_flags |= flags << 32; 663*91f16700Schasinglulu } 664*91f16700Schasinglulu 665*91f16700Schasinglulu static int is_power_of_2(unsigned long x) 666*91f16700Schasinglulu { 667*91f16700Schasinglulu return x && !(x & (x - 1)); 668*91f16700Schasinglulu } 669*91f16700Schasinglulu 670*91f16700Schasinglulu static unsigned long get_image_align(char *arg) 671*91f16700Schasinglulu { 672*91f16700Schasinglulu char *endptr; 673*91f16700Schasinglulu unsigned long align; 674*91f16700Schasinglulu 675*91f16700Schasinglulu errno = 0; 676*91f16700Schasinglulu align = strtoul(arg, &endptr, 0); 677*91f16700Schasinglulu if (*endptr != '\0' || !is_power_of_2(align) || errno != 0) 678*91f16700Schasinglulu log_errx("Invalid alignment: %s", arg); 679*91f16700Schasinglulu 680*91f16700Schasinglulu return align; 681*91f16700Schasinglulu } 682*91f16700Schasinglulu 683*91f16700Schasinglulu static void parse_blob_opt(char *arg, uuid_t *uuid, char *filename, size_t len) 684*91f16700Schasinglulu { 685*91f16700Schasinglulu char *p; 686*91f16700Schasinglulu 687*91f16700Schasinglulu for (p = strtok(arg, ","); p != NULL; p = strtok(NULL, ",")) { 688*91f16700Schasinglulu if (strncmp(p, "uuid=", strlen("uuid=")) == 0) { 689*91f16700Schasinglulu p += strlen("uuid="); 690*91f16700Schasinglulu uuid_from_str(uuid, p); 691*91f16700Schasinglulu } else if (strncmp(p, "file=", strlen("file=")) == 0) { 692*91f16700Schasinglulu p += strlen("file="); 693*91f16700Schasinglulu snprintf(filename, len, "%s", p); 694*91f16700Schasinglulu } 695*91f16700Schasinglulu } 696*91f16700Schasinglulu } 697*91f16700Schasinglulu 698*91f16700Schasinglulu static int create_cmd(int argc, char *argv[]) 699*91f16700Schasinglulu { 700*91f16700Schasinglulu struct option *opts = NULL; 701*91f16700Schasinglulu size_t nr_opts = 0; 702*91f16700Schasinglulu unsigned long long toc_flags = 0; 703*91f16700Schasinglulu unsigned long align = 1; 704*91f16700Schasinglulu 705*91f16700Schasinglulu if (argc < 2) 706*91f16700Schasinglulu create_usage(EXIT_FAILURE); 707*91f16700Schasinglulu 708*91f16700Schasinglulu opts = fill_common_opts(opts, &nr_opts, required_argument); 709*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument, 710*91f16700Schasinglulu OPT_PLAT_TOC_FLAGS); 711*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN); 712*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); 713*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, NULL, 0, 0); 714*91f16700Schasinglulu 715*91f16700Schasinglulu while (1) { 716*91f16700Schasinglulu int c, opt_index = 0; 717*91f16700Schasinglulu 718*91f16700Schasinglulu c = getopt_long(argc, argv, "b:", opts, &opt_index); 719*91f16700Schasinglulu if (c == -1) 720*91f16700Schasinglulu break; 721*91f16700Schasinglulu 722*91f16700Schasinglulu switch (c) { 723*91f16700Schasinglulu case OPT_TOC_ENTRY: { 724*91f16700Schasinglulu image_desc_t *desc; 725*91f16700Schasinglulu 726*91f16700Schasinglulu desc = lookup_image_desc_from_opt(opts[opt_index].name); 727*91f16700Schasinglulu set_image_desc_action(desc, DO_PACK, optarg); 728*91f16700Schasinglulu break; 729*91f16700Schasinglulu } 730*91f16700Schasinglulu case OPT_PLAT_TOC_FLAGS: 731*91f16700Schasinglulu parse_plat_toc_flags(optarg, &toc_flags); 732*91f16700Schasinglulu break; 733*91f16700Schasinglulu case OPT_ALIGN: 734*91f16700Schasinglulu align = get_image_align(optarg); 735*91f16700Schasinglulu break; 736*91f16700Schasinglulu case 'b': { 737*91f16700Schasinglulu char name[_UUID_STR_LEN + 1]; 738*91f16700Schasinglulu char filename[PATH_MAX] = { 0 }; 739*91f16700Schasinglulu uuid_t uuid = uuid_null; 740*91f16700Schasinglulu image_desc_t *desc; 741*91f16700Schasinglulu 742*91f16700Schasinglulu parse_blob_opt(optarg, &uuid, 743*91f16700Schasinglulu filename, sizeof(filename)); 744*91f16700Schasinglulu 745*91f16700Schasinglulu if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 || 746*91f16700Schasinglulu filename[0] == '\0') 747*91f16700Schasinglulu create_usage(EXIT_FAILURE); 748*91f16700Schasinglulu 749*91f16700Schasinglulu desc = lookup_image_desc_from_uuid(&uuid); 750*91f16700Schasinglulu if (desc == NULL) { 751*91f16700Schasinglulu uuid_to_str(name, sizeof(name), &uuid); 752*91f16700Schasinglulu desc = new_image_desc(&uuid, name, "blob"); 753*91f16700Schasinglulu add_image_desc(desc); 754*91f16700Schasinglulu } 755*91f16700Schasinglulu set_image_desc_action(desc, DO_PACK, filename); 756*91f16700Schasinglulu break; 757*91f16700Schasinglulu } 758*91f16700Schasinglulu default: 759*91f16700Schasinglulu create_usage(EXIT_FAILURE); 760*91f16700Schasinglulu } 761*91f16700Schasinglulu } 762*91f16700Schasinglulu argc -= optind; 763*91f16700Schasinglulu argv += optind; 764*91f16700Schasinglulu free(opts); 765*91f16700Schasinglulu 766*91f16700Schasinglulu if (argc == 0) 767*91f16700Schasinglulu create_usage(EXIT_SUCCESS); 768*91f16700Schasinglulu 769*91f16700Schasinglulu update_fip(); 770*91f16700Schasinglulu 771*91f16700Schasinglulu pack_images(argv[0], toc_flags, align); 772*91f16700Schasinglulu return 0; 773*91f16700Schasinglulu } 774*91f16700Schasinglulu 775*91f16700Schasinglulu static void create_usage(int exit_status) 776*91f16700Schasinglulu { 777*91f16700Schasinglulu toc_entry_t *toc_entry = toc_entries; 778*91f16700Schasinglulu 779*91f16700Schasinglulu printf("fiptool create [opts] FIP_FILENAME\n"); 780*91f16700Schasinglulu printf("\n"); 781*91f16700Schasinglulu printf("Options:\n"); 782*91f16700Schasinglulu printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n"); 783*91f16700Schasinglulu printf(" --blob uuid=...,file=...\tAdd an image with the given UUID pointed to by file.\n"); 784*91f16700Schasinglulu printf(" --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n"); 785*91f16700Schasinglulu printf("\n"); 786*91f16700Schasinglulu printf("Specific images are packed with the following options:\n"); 787*91f16700Schasinglulu for (; toc_entry->cmdline_name != NULL; toc_entry++) 788*91f16700Schasinglulu printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, 789*91f16700Schasinglulu toc_entry->name); 790*91f16700Schasinglulu #ifdef PLAT_DEF_FIP_UUID 791*91f16700Schasinglulu toc_entry = plat_def_toc_entries; 792*91f16700Schasinglulu for (; toc_entry->cmdline_name != NULL; toc_entry++) 793*91f16700Schasinglulu printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, 794*91f16700Schasinglulu toc_entry->name); 795*91f16700Schasinglulu #endif 796*91f16700Schasinglulu exit(exit_status); 797*91f16700Schasinglulu } 798*91f16700Schasinglulu 799*91f16700Schasinglulu static int update_cmd(int argc, char *argv[]) 800*91f16700Schasinglulu { 801*91f16700Schasinglulu struct option *opts = NULL; 802*91f16700Schasinglulu size_t nr_opts = 0; 803*91f16700Schasinglulu char outfile[PATH_MAX] = { 0 }; 804*91f16700Schasinglulu fip_toc_header_t toc_header = { 0 }; 805*91f16700Schasinglulu unsigned long long toc_flags = 0; 806*91f16700Schasinglulu unsigned long align = 1; 807*91f16700Schasinglulu int pflag = 0; 808*91f16700Schasinglulu 809*91f16700Schasinglulu if (argc < 2) 810*91f16700Schasinglulu update_usage(EXIT_FAILURE); 811*91f16700Schasinglulu 812*91f16700Schasinglulu opts = fill_common_opts(opts, &nr_opts, required_argument); 813*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN); 814*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); 815*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "out", required_argument, 'o'); 816*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "plat-toc-flags", required_argument, 817*91f16700Schasinglulu OPT_PLAT_TOC_FLAGS); 818*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, NULL, 0, 0); 819*91f16700Schasinglulu 820*91f16700Schasinglulu while (1) { 821*91f16700Schasinglulu int c, opt_index = 0; 822*91f16700Schasinglulu 823*91f16700Schasinglulu c = getopt_long(argc, argv, "b:o:", opts, &opt_index); 824*91f16700Schasinglulu if (c == -1) 825*91f16700Schasinglulu break; 826*91f16700Schasinglulu 827*91f16700Schasinglulu switch (c) { 828*91f16700Schasinglulu case OPT_TOC_ENTRY: { 829*91f16700Schasinglulu image_desc_t *desc; 830*91f16700Schasinglulu 831*91f16700Schasinglulu desc = lookup_image_desc_from_opt(opts[opt_index].name); 832*91f16700Schasinglulu set_image_desc_action(desc, DO_PACK, optarg); 833*91f16700Schasinglulu break; 834*91f16700Schasinglulu } 835*91f16700Schasinglulu case OPT_PLAT_TOC_FLAGS: 836*91f16700Schasinglulu parse_plat_toc_flags(optarg, &toc_flags); 837*91f16700Schasinglulu pflag = 1; 838*91f16700Schasinglulu break; 839*91f16700Schasinglulu case 'b': { 840*91f16700Schasinglulu char name[_UUID_STR_LEN + 1]; 841*91f16700Schasinglulu char filename[PATH_MAX] = { 0 }; 842*91f16700Schasinglulu uuid_t uuid = uuid_null; 843*91f16700Schasinglulu image_desc_t *desc; 844*91f16700Schasinglulu 845*91f16700Schasinglulu parse_blob_opt(optarg, &uuid, 846*91f16700Schasinglulu filename, sizeof(filename)); 847*91f16700Schasinglulu 848*91f16700Schasinglulu if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 || 849*91f16700Schasinglulu filename[0] == '\0') 850*91f16700Schasinglulu update_usage(EXIT_FAILURE); 851*91f16700Schasinglulu 852*91f16700Schasinglulu desc = lookup_image_desc_from_uuid(&uuid); 853*91f16700Schasinglulu if (desc == NULL) { 854*91f16700Schasinglulu uuid_to_str(name, sizeof(name), &uuid); 855*91f16700Schasinglulu desc = new_image_desc(&uuid, name, "blob"); 856*91f16700Schasinglulu add_image_desc(desc); 857*91f16700Schasinglulu } 858*91f16700Schasinglulu set_image_desc_action(desc, DO_PACK, filename); 859*91f16700Schasinglulu break; 860*91f16700Schasinglulu } 861*91f16700Schasinglulu case OPT_ALIGN: 862*91f16700Schasinglulu align = get_image_align(optarg); 863*91f16700Schasinglulu break; 864*91f16700Schasinglulu case 'o': 865*91f16700Schasinglulu snprintf(outfile, sizeof(outfile), "%s", optarg); 866*91f16700Schasinglulu break; 867*91f16700Schasinglulu default: 868*91f16700Schasinglulu update_usage(EXIT_FAILURE); 869*91f16700Schasinglulu } 870*91f16700Schasinglulu } 871*91f16700Schasinglulu argc -= optind; 872*91f16700Schasinglulu argv += optind; 873*91f16700Schasinglulu free(opts); 874*91f16700Schasinglulu 875*91f16700Schasinglulu if (argc == 0) 876*91f16700Schasinglulu update_usage(EXIT_SUCCESS); 877*91f16700Schasinglulu 878*91f16700Schasinglulu if (outfile[0] == '\0') 879*91f16700Schasinglulu snprintf(outfile, sizeof(outfile), "%s", argv[0]); 880*91f16700Schasinglulu 881*91f16700Schasinglulu if (access(argv[0], F_OK) == 0) 882*91f16700Schasinglulu parse_fip(argv[0], &toc_header); 883*91f16700Schasinglulu 884*91f16700Schasinglulu if (pflag) 885*91f16700Schasinglulu toc_header.flags &= ~(0xffffULL << 32); 886*91f16700Schasinglulu toc_flags = (toc_header.flags |= toc_flags); 887*91f16700Schasinglulu 888*91f16700Schasinglulu update_fip(); 889*91f16700Schasinglulu 890*91f16700Schasinglulu pack_images(outfile, toc_flags, align); 891*91f16700Schasinglulu return 0; 892*91f16700Schasinglulu } 893*91f16700Schasinglulu 894*91f16700Schasinglulu static void update_usage(int exit_status) 895*91f16700Schasinglulu { 896*91f16700Schasinglulu toc_entry_t *toc_entry = toc_entries; 897*91f16700Schasinglulu 898*91f16700Schasinglulu printf("fiptool update [opts] FIP_FILENAME\n"); 899*91f16700Schasinglulu printf("\n"); 900*91f16700Schasinglulu printf("Options:\n"); 901*91f16700Schasinglulu printf(" --align <value>\t\tEach image is aligned to <value> (default: 1).\n"); 902*91f16700Schasinglulu printf(" --blob uuid=...,file=...\tAdd or update an image with the given UUID pointed to by file.\n"); 903*91f16700Schasinglulu printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n"); 904*91f16700Schasinglulu printf(" --plat-toc-flags <value>\t16-bit platform specific flag field occupying bits 32-47 in 64-bit ToC header.\n"); 905*91f16700Schasinglulu printf("\n"); 906*91f16700Schasinglulu printf("Specific images are packed with the following options:\n"); 907*91f16700Schasinglulu for (; toc_entry->cmdline_name != NULL; toc_entry++) 908*91f16700Schasinglulu printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, 909*91f16700Schasinglulu toc_entry->name); 910*91f16700Schasinglulu #ifdef PLAT_DEF_FIP_UUID 911*91f16700Schasinglulu toc_entry = plat_def_toc_entries; 912*91f16700Schasinglulu for (; toc_entry->cmdline_name != NULL; toc_entry++) 913*91f16700Schasinglulu printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, 914*91f16700Schasinglulu toc_entry->name); 915*91f16700Schasinglulu #endif 916*91f16700Schasinglulu exit(exit_status); 917*91f16700Schasinglulu } 918*91f16700Schasinglulu 919*91f16700Schasinglulu static int unpack_cmd(int argc, char *argv[]) 920*91f16700Schasinglulu { 921*91f16700Schasinglulu struct option *opts = NULL; 922*91f16700Schasinglulu size_t nr_opts = 0; 923*91f16700Schasinglulu char outdir[PATH_MAX] = { 0 }; 924*91f16700Schasinglulu image_desc_t *desc; 925*91f16700Schasinglulu int fflag = 0; 926*91f16700Schasinglulu int unpack_all = 1; 927*91f16700Schasinglulu 928*91f16700Schasinglulu if (argc < 2) 929*91f16700Schasinglulu unpack_usage(EXIT_FAILURE); 930*91f16700Schasinglulu 931*91f16700Schasinglulu opts = fill_common_opts(opts, &nr_opts, required_argument); 932*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); 933*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "force", no_argument, 'f'); 934*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "out", required_argument, 'o'); 935*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, NULL, 0, 0); 936*91f16700Schasinglulu 937*91f16700Schasinglulu while (1) { 938*91f16700Schasinglulu int c, opt_index = 0; 939*91f16700Schasinglulu 940*91f16700Schasinglulu c = getopt_long(argc, argv, "b:fo:", opts, &opt_index); 941*91f16700Schasinglulu if (c == -1) 942*91f16700Schasinglulu break; 943*91f16700Schasinglulu 944*91f16700Schasinglulu switch (c) { 945*91f16700Schasinglulu case OPT_TOC_ENTRY: { 946*91f16700Schasinglulu image_desc_t *desc; 947*91f16700Schasinglulu 948*91f16700Schasinglulu desc = lookup_image_desc_from_opt(opts[opt_index].name); 949*91f16700Schasinglulu set_image_desc_action(desc, DO_UNPACK, optarg); 950*91f16700Schasinglulu unpack_all = 0; 951*91f16700Schasinglulu break; 952*91f16700Schasinglulu } 953*91f16700Schasinglulu case 'b': { 954*91f16700Schasinglulu char name[_UUID_STR_LEN + 1]; 955*91f16700Schasinglulu char filename[PATH_MAX] = { 0 }; 956*91f16700Schasinglulu uuid_t uuid = uuid_null; 957*91f16700Schasinglulu image_desc_t *desc; 958*91f16700Schasinglulu 959*91f16700Schasinglulu parse_blob_opt(optarg, &uuid, 960*91f16700Schasinglulu filename, sizeof(filename)); 961*91f16700Schasinglulu 962*91f16700Schasinglulu if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0 || 963*91f16700Schasinglulu filename[0] == '\0') 964*91f16700Schasinglulu unpack_usage(EXIT_FAILURE); 965*91f16700Schasinglulu 966*91f16700Schasinglulu desc = lookup_image_desc_from_uuid(&uuid); 967*91f16700Schasinglulu if (desc == NULL) { 968*91f16700Schasinglulu uuid_to_str(name, sizeof(name), &uuid); 969*91f16700Schasinglulu desc = new_image_desc(&uuid, name, "blob"); 970*91f16700Schasinglulu add_image_desc(desc); 971*91f16700Schasinglulu } 972*91f16700Schasinglulu set_image_desc_action(desc, DO_UNPACK, filename); 973*91f16700Schasinglulu unpack_all = 0; 974*91f16700Schasinglulu break; 975*91f16700Schasinglulu } 976*91f16700Schasinglulu case 'f': 977*91f16700Schasinglulu fflag = 1; 978*91f16700Schasinglulu break; 979*91f16700Schasinglulu case 'o': 980*91f16700Schasinglulu snprintf(outdir, sizeof(outdir), "%s", optarg); 981*91f16700Schasinglulu break; 982*91f16700Schasinglulu default: 983*91f16700Schasinglulu unpack_usage(EXIT_FAILURE); 984*91f16700Schasinglulu } 985*91f16700Schasinglulu } 986*91f16700Schasinglulu argc -= optind; 987*91f16700Schasinglulu argv += optind; 988*91f16700Schasinglulu free(opts); 989*91f16700Schasinglulu 990*91f16700Schasinglulu if (argc == 0) 991*91f16700Schasinglulu unpack_usage(EXIT_SUCCESS); 992*91f16700Schasinglulu 993*91f16700Schasinglulu parse_fip(argv[0], NULL); 994*91f16700Schasinglulu 995*91f16700Schasinglulu if (outdir[0] != '\0') 996*91f16700Schasinglulu if (chdir(outdir) == -1) 997*91f16700Schasinglulu log_err("chdir %s", outdir); 998*91f16700Schasinglulu 999*91f16700Schasinglulu /* Unpack all specified images. */ 1000*91f16700Schasinglulu for (desc = image_desc_head; desc != NULL; desc = desc->next) { 1001*91f16700Schasinglulu char file[PATH_MAX]; 1002*91f16700Schasinglulu image_t *image = desc->image; 1003*91f16700Schasinglulu 1004*91f16700Schasinglulu if (!unpack_all && desc->action != DO_UNPACK) 1005*91f16700Schasinglulu continue; 1006*91f16700Schasinglulu 1007*91f16700Schasinglulu /* Build filename. */ 1008*91f16700Schasinglulu if (desc->action_arg == NULL) 1009*91f16700Schasinglulu snprintf(file, sizeof(file), "%s.bin", 1010*91f16700Schasinglulu desc->cmdline_name); 1011*91f16700Schasinglulu else 1012*91f16700Schasinglulu snprintf(file, sizeof(file), "%s", 1013*91f16700Schasinglulu desc->action_arg); 1014*91f16700Schasinglulu 1015*91f16700Schasinglulu if (image == NULL) { 1016*91f16700Schasinglulu if (!unpack_all) 1017*91f16700Schasinglulu log_warnx("%s does not exist in %s", 1018*91f16700Schasinglulu file, argv[0]); 1019*91f16700Schasinglulu continue; 1020*91f16700Schasinglulu } 1021*91f16700Schasinglulu 1022*91f16700Schasinglulu if (access(file, F_OK) != 0 || fflag) { 1023*91f16700Schasinglulu if (verbose) 1024*91f16700Schasinglulu log_dbgx("Unpacking %s", file); 1025*91f16700Schasinglulu write_image_to_file(image, file); 1026*91f16700Schasinglulu } else { 1027*91f16700Schasinglulu log_warnx("File %s already exists, use --force to overwrite it", 1028*91f16700Schasinglulu file); 1029*91f16700Schasinglulu } 1030*91f16700Schasinglulu } 1031*91f16700Schasinglulu 1032*91f16700Schasinglulu return 0; 1033*91f16700Schasinglulu } 1034*91f16700Schasinglulu 1035*91f16700Schasinglulu static void unpack_usage(int exit_status) 1036*91f16700Schasinglulu { 1037*91f16700Schasinglulu toc_entry_t *toc_entry = toc_entries; 1038*91f16700Schasinglulu 1039*91f16700Schasinglulu printf("fiptool unpack [opts] FIP_FILENAME\n"); 1040*91f16700Schasinglulu printf("\n"); 1041*91f16700Schasinglulu printf("Options:\n"); 1042*91f16700Schasinglulu printf(" --blob uuid=...,file=...\tUnpack an image with the given UUID to file.\n"); 1043*91f16700Schasinglulu printf(" --force\t\t\tIf the output file already exists, use --force to overwrite it.\n"); 1044*91f16700Schasinglulu printf(" --out path\t\t\tSet the output directory path.\n"); 1045*91f16700Schasinglulu printf("\n"); 1046*91f16700Schasinglulu printf("Specific images are unpacked with the following options:\n"); 1047*91f16700Schasinglulu for (; toc_entry->cmdline_name != NULL; toc_entry++) 1048*91f16700Schasinglulu printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, 1049*91f16700Schasinglulu toc_entry->name); 1050*91f16700Schasinglulu #ifdef PLAT_DEF_FIP_UUID 1051*91f16700Schasinglulu toc_entry = plat_def_toc_entries; 1052*91f16700Schasinglulu for (; toc_entry->cmdline_name != NULL; toc_entry++) 1053*91f16700Schasinglulu printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, 1054*91f16700Schasinglulu toc_entry->name); 1055*91f16700Schasinglulu #endif 1056*91f16700Schasinglulu printf("\n"); 1057*91f16700Schasinglulu printf("If no options are provided, all images will be unpacked.\n"); 1058*91f16700Schasinglulu exit(exit_status); 1059*91f16700Schasinglulu } 1060*91f16700Schasinglulu 1061*91f16700Schasinglulu static int remove_cmd(int argc, char *argv[]) 1062*91f16700Schasinglulu { 1063*91f16700Schasinglulu struct option *opts = NULL; 1064*91f16700Schasinglulu size_t nr_opts = 0; 1065*91f16700Schasinglulu char outfile[PATH_MAX] = { 0 }; 1066*91f16700Schasinglulu fip_toc_header_t toc_header; 1067*91f16700Schasinglulu image_desc_t *desc; 1068*91f16700Schasinglulu unsigned long align = 1; 1069*91f16700Schasinglulu int fflag = 0; 1070*91f16700Schasinglulu 1071*91f16700Schasinglulu if (argc < 2) 1072*91f16700Schasinglulu remove_usage(EXIT_FAILURE); 1073*91f16700Schasinglulu 1074*91f16700Schasinglulu opts = fill_common_opts(opts, &nr_opts, no_argument); 1075*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "align", required_argument, OPT_ALIGN); 1076*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "blob", required_argument, 'b'); 1077*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "force", no_argument, 'f'); 1078*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, "out", required_argument, 'o'); 1079*91f16700Schasinglulu opts = add_opt(opts, &nr_opts, NULL, 0, 0); 1080*91f16700Schasinglulu 1081*91f16700Schasinglulu while (1) { 1082*91f16700Schasinglulu int c, opt_index = 0; 1083*91f16700Schasinglulu 1084*91f16700Schasinglulu c = getopt_long(argc, argv, "b:fo:", opts, &opt_index); 1085*91f16700Schasinglulu if (c == -1) 1086*91f16700Schasinglulu break; 1087*91f16700Schasinglulu 1088*91f16700Schasinglulu switch (c) { 1089*91f16700Schasinglulu case OPT_TOC_ENTRY: { 1090*91f16700Schasinglulu image_desc_t *desc; 1091*91f16700Schasinglulu 1092*91f16700Schasinglulu desc = lookup_image_desc_from_opt(opts[opt_index].name); 1093*91f16700Schasinglulu set_image_desc_action(desc, DO_REMOVE, NULL); 1094*91f16700Schasinglulu break; 1095*91f16700Schasinglulu } 1096*91f16700Schasinglulu case OPT_ALIGN: 1097*91f16700Schasinglulu align = get_image_align(optarg); 1098*91f16700Schasinglulu break; 1099*91f16700Schasinglulu case 'b': { 1100*91f16700Schasinglulu char name[_UUID_STR_LEN + 1], filename[PATH_MAX]; 1101*91f16700Schasinglulu uuid_t uuid = uuid_null; 1102*91f16700Schasinglulu image_desc_t *desc; 1103*91f16700Schasinglulu 1104*91f16700Schasinglulu parse_blob_opt(optarg, &uuid, 1105*91f16700Schasinglulu filename, sizeof(filename)); 1106*91f16700Schasinglulu 1107*91f16700Schasinglulu if (memcmp(&uuid, &uuid_null, sizeof(uuid_t)) == 0) 1108*91f16700Schasinglulu remove_usage(EXIT_FAILURE); 1109*91f16700Schasinglulu 1110*91f16700Schasinglulu desc = lookup_image_desc_from_uuid(&uuid); 1111*91f16700Schasinglulu if (desc == NULL) { 1112*91f16700Schasinglulu uuid_to_str(name, sizeof(name), &uuid); 1113*91f16700Schasinglulu desc = new_image_desc(&uuid, name, "blob"); 1114*91f16700Schasinglulu add_image_desc(desc); 1115*91f16700Schasinglulu } 1116*91f16700Schasinglulu set_image_desc_action(desc, DO_REMOVE, NULL); 1117*91f16700Schasinglulu break; 1118*91f16700Schasinglulu } 1119*91f16700Schasinglulu case 'f': 1120*91f16700Schasinglulu fflag = 1; 1121*91f16700Schasinglulu break; 1122*91f16700Schasinglulu case 'o': 1123*91f16700Schasinglulu snprintf(outfile, sizeof(outfile), "%s", optarg); 1124*91f16700Schasinglulu break; 1125*91f16700Schasinglulu default: 1126*91f16700Schasinglulu remove_usage(EXIT_FAILURE); 1127*91f16700Schasinglulu } 1128*91f16700Schasinglulu } 1129*91f16700Schasinglulu argc -= optind; 1130*91f16700Schasinglulu argv += optind; 1131*91f16700Schasinglulu free(opts); 1132*91f16700Schasinglulu 1133*91f16700Schasinglulu if (argc == 0) 1134*91f16700Schasinglulu remove_usage(EXIT_SUCCESS); 1135*91f16700Schasinglulu 1136*91f16700Schasinglulu if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag) 1137*91f16700Schasinglulu log_errx("File %s already exists, use --force to overwrite it", 1138*91f16700Schasinglulu outfile); 1139*91f16700Schasinglulu 1140*91f16700Schasinglulu if (outfile[0] == '\0') 1141*91f16700Schasinglulu snprintf(outfile, sizeof(outfile), "%s", argv[0]); 1142*91f16700Schasinglulu 1143*91f16700Schasinglulu parse_fip(argv[0], &toc_header); 1144*91f16700Schasinglulu 1145*91f16700Schasinglulu for (desc = image_desc_head; desc != NULL; desc = desc->next) { 1146*91f16700Schasinglulu if (desc->action != DO_REMOVE) 1147*91f16700Schasinglulu continue; 1148*91f16700Schasinglulu 1149*91f16700Schasinglulu if (desc->image != NULL) { 1150*91f16700Schasinglulu if (verbose) 1151*91f16700Schasinglulu log_dbgx("Removing %s", 1152*91f16700Schasinglulu desc->cmdline_name); 1153*91f16700Schasinglulu free(desc->image); 1154*91f16700Schasinglulu desc->image = NULL; 1155*91f16700Schasinglulu } else { 1156*91f16700Schasinglulu log_warnx("%s does not exist in %s", 1157*91f16700Schasinglulu desc->cmdline_name, argv[0]); 1158*91f16700Schasinglulu } 1159*91f16700Schasinglulu } 1160*91f16700Schasinglulu 1161*91f16700Schasinglulu pack_images(outfile, toc_header.flags, align); 1162*91f16700Schasinglulu return 0; 1163*91f16700Schasinglulu } 1164*91f16700Schasinglulu 1165*91f16700Schasinglulu static void remove_usage(int exit_status) 1166*91f16700Schasinglulu { 1167*91f16700Schasinglulu toc_entry_t *toc_entry = toc_entries; 1168*91f16700Schasinglulu 1169*91f16700Schasinglulu printf("fiptool remove [opts] FIP_FILENAME\n"); 1170*91f16700Schasinglulu printf("\n"); 1171*91f16700Schasinglulu printf("Options:\n"); 1172*91f16700Schasinglulu printf(" --align <value>\tEach image is aligned to <value> (default: 1).\n"); 1173*91f16700Schasinglulu printf(" --blob uuid=...\tRemove an image with the given UUID.\n"); 1174*91f16700Schasinglulu printf(" --force\t\tIf the output FIP file already exists, use --force to overwrite it.\n"); 1175*91f16700Schasinglulu printf(" --out FIP_FILENAME\tSet an alternative output FIP file.\n"); 1176*91f16700Schasinglulu printf("\n"); 1177*91f16700Schasinglulu printf("Specific images are removed with the following options:\n"); 1178*91f16700Schasinglulu for (; toc_entry->cmdline_name != NULL; toc_entry++) 1179*91f16700Schasinglulu printf(" --%-16s\t%s\n", toc_entry->cmdline_name, 1180*91f16700Schasinglulu toc_entry->name); 1181*91f16700Schasinglulu #ifdef PLAT_DEF_FIP_UUID 1182*91f16700Schasinglulu toc_entry = plat_def_toc_entries; 1183*91f16700Schasinglulu for (; toc_entry->cmdline_name != NULL; toc_entry++) 1184*91f16700Schasinglulu printf(" --%-16s\t%s\n", toc_entry->cmdline_name, 1185*91f16700Schasinglulu toc_entry->name); 1186*91f16700Schasinglulu #endif 1187*91f16700Schasinglulu exit(exit_status); 1188*91f16700Schasinglulu } 1189*91f16700Schasinglulu 1190*91f16700Schasinglulu static int version_cmd(int argc, char *argv[]) 1191*91f16700Schasinglulu { 1192*91f16700Schasinglulu #ifdef VERSION 1193*91f16700Schasinglulu puts(VERSION); 1194*91f16700Schasinglulu #else 1195*91f16700Schasinglulu /* If built from fiptool directory, VERSION is not set. */ 1196*91f16700Schasinglulu puts("Unknown version"); 1197*91f16700Schasinglulu #endif 1198*91f16700Schasinglulu return 0; 1199*91f16700Schasinglulu } 1200*91f16700Schasinglulu 1201*91f16700Schasinglulu static void version_usage(int exit_status) 1202*91f16700Schasinglulu { 1203*91f16700Schasinglulu printf("fiptool version\n"); 1204*91f16700Schasinglulu exit(exit_status); 1205*91f16700Schasinglulu } 1206*91f16700Schasinglulu 1207*91f16700Schasinglulu static int help_cmd(int argc, char *argv[]) 1208*91f16700Schasinglulu { 1209*91f16700Schasinglulu int i; 1210*91f16700Schasinglulu 1211*91f16700Schasinglulu if (argc < 2) 1212*91f16700Schasinglulu usage(); 1213*91f16700Schasinglulu argc--, argv++; 1214*91f16700Schasinglulu 1215*91f16700Schasinglulu for (i = 0; i < NELEM(cmds); i++) { 1216*91f16700Schasinglulu if (strcmp(cmds[i].name, argv[0]) == 0 && 1217*91f16700Schasinglulu cmds[i].usage != NULL) 1218*91f16700Schasinglulu cmds[i].usage(EXIT_SUCCESS); 1219*91f16700Schasinglulu } 1220*91f16700Schasinglulu if (i == NELEM(cmds)) 1221*91f16700Schasinglulu printf("No help for subcommand '%s'\n", argv[0]); 1222*91f16700Schasinglulu return 0; 1223*91f16700Schasinglulu } 1224*91f16700Schasinglulu 1225*91f16700Schasinglulu static void usage(void) 1226*91f16700Schasinglulu { 1227*91f16700Schasinglulu printf("usage: fiptool [--verbose] <command> [<args>]\n"); 1228*91f16700Schasinglulu printf("Global options supported:\n"); 1229*91f16700Schasinglulu printf(" --verbose\tEnable verbose output for all commands.\n"); 1230*91f16700Schasinglulu printf("\n"); 1231*91f16700Schasinglulu printf("Commands supported:\n"); 1232*91f16700Schasinglulu printf(" info\t\tList images contained in FIP.\n"); 1233*91f16700Schasinglulu printf(" create\tCreate a new FIP with the given images.\n"); 1234*91f16700Schasinglulu printf(" update\tUpdate an existing FIP with the given images.\n"); 1235*91f16700Schasinglulu printf(" unpack\tUnpack images from FIP.\n"); 1236*91f16700Schasinglulu printf(" remove\tRemove images from FIP.\n"); 1237*91f16700Schasinglulu printf(" version\tShow fiptool version.\n"); 1238*91f16700Schasinglulu printf(" help\t\tShow help for given command.\n"); 1239*91f16700Schasinglulu exit(EXIT_SUCCESS); 1240*91f16700Schasinglulu } 1241*91f16700Schasinglulu 1242*91f16700Schasinglulu int main(int argc, char *argv[]) 1243*91f16700Schasinglulu { 1244*91f16700Schasinglulu int i, ret = 0; 1245*91f16700Schasinglulu 1246*91f16700Schasinglulu while (1) { 1247*91f16700Schasinglulu int c, opt_index = 0; 1248*91f16700Schasinglulu static struct option opts[] = { 1249*91f16700Schasinglulu { "verbose", no_argument, NULL, 'v' }, 1250*91f16700Schasinglulu { NULL, no_argument, NULL, 0 } 1251*91f16700Schasinglulu }; 1252*91f16700Schasinglulu 1253*91f16700Schasinglulu /* 1254*91f16700Schasinglulu * Set POSIX mode so getopt stops at the first non-option 1255*91f16700Schasinglulu * which is the subcommand. 1256*91f16700Schasinglulu */ 1257*91f16700Schasinglulu c = getopt_long(argc, argv, "+v", opts, &opt_index); 1258*91f16700Schasinglulu if (c == -1) 1259*91f16700Schasinglulu break; 1260*91f16700Schasinglulu 1261*91f16700Schasinglulu switch (c) { 1262*91f16700Schasinglulu case 'v': 1263*91f16700Schasinglulu verbose = 1; 1264*91f16700Schasinglulu break; 1265*91f16700Schasinglulu default: 1266*91f16700Schasinglulu usage(); 1267*91f16700Schasinglulu } 1268*91f16700Schasinglulu } 1269*91f16700Schasinglulu argc -= optind; 1270*91f16700Schasinglulu argv += optind; 1271*91f16700Schasinglulu /* Reset optind for subsequent getopt processing. */ 1272*91f16700Schasinglulu optind = 0; 1273*91f16700Schasinglulu 1274*91f16700Schasinglulu if (argc == 0) 1275*91f16700Schasinglulu usage(); 1276*91f16700Schasinglulu 1277*91f16700Schasinglulu fill_image_descs(); 1278*91f16700Schasinglulu for (i = 0; i < NELEM(cmds); i++) { 1279*91f16700Schasinglulu if (strcmp(cmds[i].name, argv[0]) == 0) { 1280*91f16700Schasinglulu ret = cmds[i].handler(argc, argv); 1281*91f16700Schasinglulu break; 1282*91f16700Schasinglulu } 1283*91f16700Schasinglulu } 1284*91f16700Schasinglulu if (i == NELEM(cmds)) 1285*91f16700Schasinglulu usage(); 1286*91f16700Schasinglulu free_image_descs(); 1287*91f16700Schasinglulu return ret; 1288*91f16700Schasinglulu } 1289