1*819281eeSdp-arm /* 2*819281eeSdp-arm * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. 3*819281eeSdp-arm * 4*819281eeSdp-arm * Redistribution and use in source and binary forms, with or without 5*819281eeSdp-arm * modification, are permitted provided that the following conditions are met: 6*819281eeSdp-arm * 7*819281eeSdp-arm * Redistributions of source code must retain the above copyright notice, this 8*819281eeSdp-arm * list of conditions and the following disclaimer. 9*819281eeSdp-arm * 10*819281eeSdp-arm * Redistributions in binary form must reproduce the above copyright notice, 11*819281eeSdp-arm * this list of conditions and the following disclaimer in the documentation 12*819281eeSdp-arm * and/or other materials provided with the distribution. 13*819281eeSdp-arm * 14*819281eeSdp-arm * Neither the name of ARM nor the names of its contributors may be used 15*819281eeSdp-arm * to endorse or promote products derived from this software without specific 16*819281eeSdp-arm * prior written permission. 17*819281eeSdp-arm * 18*819281eeSdp-arm * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*819281eeSdp-arm * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*819281eeSdp-arm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*819281eeSdp-arm * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*819281eeSdp-arm * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*819281eeSdp-arm * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*819281eeSdp-arm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*819281eeSdp-arm * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*819281eeSdp-arm * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*819281eeSdp-arm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*819281eeSdp-arm * POSSIBILITY OF SUCH DAMAGE. 29*819281eeSdp-arm */ 30*819281eeSdp-arm 31*819281eeSdp-arm #include <sys/types.h> 32*819281eeSdp-arm #include <sys/stat.h> 33*819281eeSdp-arm 34*819281eeSdp-arm #include <assert.h> 35*819281eeSdp-arm #include <errno.h> 36*819281eeSdp-arm #include <getopt.h> 37*819281eeSdp-arm #include <limits.h> 38*819281eeSdp-arm #include <stdarg.h> 39*819281eeSdp-arm #include <stdint.h> 40*819281eeSdp-arm #include <stdio.h> 41*819281eeSdp-arm #include <stdlib.h> 42*819281eeSdp-arm #include <string.h> 43*819281eeSdp-arm #include <unistd.h> 44*819281eeSdp-arm 45*819281eeSdp-arm #include "fiptool.h" 46*819281eeSdp-arm #include "firmware_image_package.h" 47*819281eeSdp-arm #include "tbbr_config.h" 48*819281eeSdp-arm 49*819281eeSdp-arm #define OPT_TOC_ENTRY 0 50*819281eeSdp-arm #define OPT_PLAT_TOC_FLAGS 1 51*819281eeSdp-arm 52*819281eeSdp-arm static int info_cmd(int argc, char *argv[]); 53*819281eeSdp-arm static void info_usage(void); 54*819281eeSdp-arm static int create_cmd(int argc, char *argv[]); 55*819281eeSdp-arm static void create_usage(void); 56*819281eeSdp-arm static int update_cmd(int argc, char *argv[]); 57*819281eeSdp-arm static void update_usage(void); 58*819281eeSdp-arm static int unpack_cmd(int argc, char *argv[]); 59*819281eeSdp-arm static void unpack_usage(void); 60*819281eeSdp-arm static int remove_cmd(int argc, char *argv[]); 61*819281eeSdp-arm static void remove_usage(void); 62*819281eeSdp-arm static int version_cmd(int argc, char *argv[]); 63*819281eeSdp-arm static void version_usage(void); 64*819281eeSdp-arm static int help_cmd(int argc, char *argv[]); 65*819281eeSdp-arm static void usage(void); 66*819281eeSdp-arm 67*819281eeSdp-arm /* Available subcommands. */ 68*819281eeSdp-arm static cmd_t cmds[] = { 69*819281eeSdp-arm { .name = "info", .handler = info_cmd, .usage = info_usage }, 70*819281eeSdp-arm { .name = "create", .handler = create_cmd, .usage = create_usage }, 71*819281eeSdp-arm { .name = "update", .handler = update_cmd, .usage = update_usage }, 72*819281eeSdp-arm { .name = "unpack", .handler = unpack_cmd, .usage = unpack_usage }, 73*819281eeSdp-arm { .name = "remove", .handler = remove_cmd, .usage = remove_usage }, 74*819281eeSdp-arm { .name = "version", .handler = version_cmd, .usage = version_usage }, 75*819281eeSdp-arm { .name = "help", .handler = help_cmd, .usage = NULL }, 76*819281eeSdp-arm }; 77*819281eeSdp-arm 78*819281eeSdp-arm static image_t *images[MAX_IMAGES]; 79*819281eeSdp-arm static size_t nr_images; 80*819281eeSdp-arm static uuid_t uuid_null = { 0 }; 81*819281eeSdp-arm static int verbose; 82*819281eeSdp-arm 83*819281eeSdp-arm static void vlog(int prio, char *msg, va_list ap) 84*819281eeSdp-arm { 85*819281eeSdp-arm char *prefix[] = { "DEBUG", "WARN", "ERROR" }; 86*819281eeSdp-arm 87*819281eeSdp-arm fprintf(stderr, "%s: ", prefix[prio]); 88*819281eeSdp-arm vfprintf(stderr, msg, ap); 89*819281eeSdp-arm fputc('\n', stderr); 90*819281eeSdp-arm } 91*819281eeSdp-arm 92*819281eeSdp-arm static void log_dbgx(char *msg, ...) 93*819281eeSdp-arm { 94*819281eeSdp-arm va_list ap; 95*819281eeSdp-arm 96*819281eeSdp-arm va_start(ap, msg); 97*819281eeSdp-arm vlog(LOG_DBG, msg, ap); 98*819281eeSdp-arm va_end(ap); 99*819281eeSdp-arm } 100*819281eeSdp-arm 101*819281eeSdp-arm static void log_warnx(char *msg, ...) 102*819281eeSdp-arm { 103*819281eeSdp-arm va_list ap; 104*819281eeSdp-arm 105*819281eeSdp-arm va_start(ap, msg); 106*819281eeSdp-arm vlog(LOG_WARN, msg, ap); 107*819281eeSdp-arm va_end(ap); 108*819281eeSdp-arm } 109*819281eeSdp-arm 110*819281eeSdp-arm static void log_err(char *msg, ...) 111*819281eeSdp-arm { 112*819281eeSdp-arm char buf[512]; 113*819281eeSdp-arm va_list ap; 114*819281eeSdp-arm 115*819281eeSdp-arm va_start(ap, msg); 116*819281eeSdp-arm snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno)); 117*819281eeSdp-arm vlog(LOG_ERR, buf, ap); 118*819281eeSdp-arm va_end(ap); 119*819281eeSdp-arm exit(1); 120*819281eeSdp-arm } 121*819281eeSdp-arm 122*819281eeSdp-arm static void log_errx(char *msg, ...) 123*819281eeSdp-arm { 124*819281eeSdp-arm va_list ap; 125*819281eeSdp-arm 126*819281eeSdp-arm va_start(ap, msg); 127*819281eeSdp-arm vlog(LOG_ERR, msg, ap); 128*819281eeSdp-arm va_end(ap); 129*819281eeSdp-arm exit(1); 130*819281eeSdp-arm } 131*819281eeSdp-arm 132*819281eeSdp-arm static void add_image(image_t *image) 133*819281eeSdp-arm { 134*819281eeSdp-arm if (nr_images + 1 > MAX_IMAGES) 135*819281eeSdp-arm log_errx("Too many images"); 136*819281eeSdp-arm images[nr_images++] = image; 137*819281eeSdp-arm } 138*819281eeSdp-arm 139*819281eeSdp-arm static void free_image(image_t *image) 140*819281eeSdp-arm { 141*819281eeSdp-arm free(image->buffer); 142*819281eeSdp-arm free(image); 143*819281eeSdp-arm } 144*819281eeSdp-arm 145*819281eeSdp-arm static void replace_image(image_t *image_dst, image_t *image_src) 146*819281eeSdp-arm { 147*819281eeSdp-arm int i; 148*819281eeSdp-arm 149*819281eeSdp-arm for (i = 0; i < nr_images; i++) { 150*819281eeSdp-arm if (images[i] == image_dst) { 151*819281eeSdp-arm free_image(images[i]); 152*819281eeSdp-arm images[i] = image_src; 153*819281eeSdp-arm break; 154*819281eeSdp-arm } 155*819281eeSdp-arm } 156*819281eeSdp-arm assert(i != nr_images); 157*819281eeSdp-arm } 158*819281eeSdp-arm 159*819281eeSdp-arm static void remove_image(image_t *image) 160*819281eeSdp-arm { 161*819281eeSdp-arm int i; 162*819281eeSdp-arm 163*819281eeSdp-arm for (i = 0; i < nr_images; i++) { 164*819281eeSdp-arm if (images[i] == image) { 165*819281eeSdp-arm free_image(images[i]); 166*819281eeSdp-arm images[i] = NULL; 167*819281eeSdp-arm break; 168*819281eeSdp-arm } 169*819281eeSdp-arm } 170*819281eeSdp-arm assert(i != nr_images); 171*819281eeSdp-arm 172*819281eeSdp-arm /* Compact array. */ 173*819281eeSdp-arm memmove(&images[i], &images[i + 1], 174*819281eeSdp-arm (nr_images - i - 1) * sizeof(*images)); 175*819281eeSdp-arm nr_images--; 176*819281eeSdp-arm } 177*819281eeSdp-arm 178*819281eeSdp-arm static void free_images(void) 179*819281eeSdp-arm { 180*819281eeSdp-arm int i; 181*819281eeSdp-arm 182*819281eeSdp-arm for (i = 0; i < nr_images; i++) { 183*819281eeSdp-arm free_image(images[i]); 184*819281eeSdp-arm images[i] = NULL; 185*819281eeSdp-arm } 186*819281eeSdp-arm } 187*819281eeSdp-arm 188*819281eeSdp-arm static toc_entry_t *get_entry_lookup_from_uuid(const uuid_t *uuid) 189*819281eeSdp-arm { 190*819281eeSdp-arm toc_entry_t *toc_entry = toc_entries; 191*819281eeSdp-arm 192*819281eeSdp-arm for (; toc_entry->cmdline_name != NULL; toc_entry++) 193*819281eeSdp-arm if (memcmp(&toc_entry->uuid, uuid, sizeof(uuid_t)) == 0) 194*819281eeSdp-arm return toc_entry; 195*819281eeSdp-arm return NULL; 196*819281eeSdp-arm } 197*819281eeSdp-arm 198*819281eeSdp-arm static int parse_fip(char *filename, fip_toc_header_t *toc_header_out) 199*819281eeSdp-arm { 200*819281eeSdp-arm struct stat st; 201*819281eeSdp-arm FILE *fp; 202*819281eeSdp-arm char *buf, *bufend; 203*819281eeSdp-arm fip_toc_header_t *toc_header; 204*819281eeSdp-arm fip_toc_entry_t *toc_entry; 205*819281eeSdp-arm image_t *image; 206*819281eeSdp-arm int terminated = 0; 207*819281eeSdp-arm 208*819281eeSdp-arm fp = fopen(filename, "r"); 209*819281eeSdp-arm if (fp == NULL) 210*819281eeSdp-arm log_err("fopen %s", filename); 211*819281eeSdp-arm 212*819281eeSdp-arm if (fstat(fileno(fp), &st) == -1) 213*819281eeSdp-arm log_err("fstat %s", filename); 214*819281eeSdp-arm 215*819281eeSdp-arm buf = malloc(st.st_size); 216*819281eeSdp-arm if (buf == NULL) 217*819281eeSdp-arm log_err("malloc"); 218*819281eeSdp-arm 219*819281eeSdp-arm if (fread(buf, 1, st.st_size, fp) != st.st_size) 220*819281eeSdp-arm log_errx("Failed to read %s", filename); 221*819281eeSdp-arm bufend = buf + st.st_size; 222*819281eeSdp-arm fclose(fp); 223*819281eeSdp-arm 224*819281eeSdp-arm if (st.st_size < sizeof(fip_toc_header_t)) 225*819281eeSdp-arm log_errx("FIP %s is truncated", filename); 226*819281eeSdp-arm 227*819281eeSdp-arm toc_header = (fip_toc_header_t *)buf; 228*819281eeSdp-arm toc_entry = (fip_toc_entry_t *)(toc_header + 1); 229*819281eeSdp-arm 230*819281eeSdp-arm if (toc_header->name != TOC_HEADER_NAME) 231*819281eeSdp-arm log_errx("%s is not a FIP file", filename); 232*819281eeSdp-arm 233*819281eeSdp-arm /* Return the ToC header if the caller wants it. */ 234*819281eeSdp-arm if (toc_header_out != NULL) 235*819281eeSdp-arm *toc_header_out = *toc_header; 236*819281eeSdp-arm 237*819281eeSdp-arm /* Walk through each ToC entry in the file. */ 238*819281eeSdp-arm while ((char *)toc_entry + sizeof(*toc_entry) - 1 < bufend) { 239*819281eeSdp-arm /* Found the ToC terminator, we are done. */ 240*819281eeSdp-arm if (memcmp(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)) == 0) { 241*819281eeSdp-arm terminated = 1; 242*819281eeSdp-arm break; 243*819281eeSdp-arm } 244*819281eeSdp-arm 245*819281eeSdp-arm /* 246*819281eeSdp-arm * Build a new image out of the ToC entry and add it to the 247*819281eeSdp-arm * table of images. 248*819281eeSdp-arm */ 249*819281eeSdp-arm image = malloc(sizeof(*image)); 250*819281eeSdp-arm if (image == NULL) 251*819281eeSdp-arm log_err("malloc"); 252*819281eeSdp-arm 253*819281eeSdp-arm memcpy(&image->uuid, &toc_entry->uuid, sizeof(uuid_t)); 254*819281eeSdp-arm 255*819281eeSdp-arm image->buffer = malloc(toc_entry->size); 256*819281eeSdp-arm if (image->buffer == NULL) 257*819281eeSdp-arm log_err("malloc"); 258*819281eeSdp-arm 259*819281eeSdp-arm /* Overflow checks before memory copy. */ 260*819281eeSdp-arm if (toc_entry->size > (uint64_t)-1 - toc_entry->offset_address) 261*819281eeSdp-arm log_errx("FIP %s is corrupted", filename); 262*819281eeSdp-arm if (toc_entry->size + toc_entry->offset_address > st.st_size) 263*819281eeSdp-arm log_errx("FIP %s is corrupted", filename); 264*819281eeSdp-arm 265*819281eeSdp-arm memcpy(image->buffer, buf + toc_entry->offset_address, 266*819281eeSdp-arm toc_entry->size); 267*819281eeSdp-arm image->size = toc_entry->size; 268*819281eeSdp-arm 269*819281eeSdp-arm image->toc_entry = get_entry_lookup_from_uuid(&toc_entry->uuid); 270*819281eeSdp-arm if (image->toc_entry == NULL) { 271*819281eeSdp-arm add_image(image); 272*819281eeSdp-arm toc_entry++; 273*819281eeSdp-arm continue; 274*819281eeSdp-arm } 275*819281eeSdp-arm 276*819281eeSdp-arm assert(image->toc_entry->image == NULL); 277*819281eeSdp-arm /* Link backpointer from lookup entry. */ 278*819281eeSdp-arm image->toc_entry->image = image; 279*819281eeSdp-arm add_image(image); 280*819281eeSdp-arm 281*819281eeSdp-arm toc_entry++; 282*819281eeSdp-arm } 283*819281eeSdp-arm 284*819281eeSdp-arm if (terminated == 0) 285*819281eeSdp-arm log_errx("FIP %s does not have a ToC terminator entry", 286*819281eeSdp-arm filename); 287*819281eeSdp-arm free(buf); 288*819281eeSdp-arm return 0; 289*819281eeSdp-arm } 290*819281eeSdp-arm 291*819281eeSdp-arm static image_t *read_image_from_file(toc_entry_t *toc_entry, char *filename) 292*819281eeSdp-arm { 293*819281eeSdp-arm struct stat st; 294*819281eeSdp-arm image_t *image; 295*819281eeSdp-arm FILE *fp; 296*819281eeSdp-arm 297*819281eeSdp-arm fp = fopen(filename, "r"); 298*819281eeSdp-arm if (fp == NULL) 299*819281eeSdp-arm log_err("fopen %s", filename); 300*819281eeSdp-arm 301*819281eeSdp-arm if (fstat(fileno(fp), &st) == -1) 302*819281eeSdp-arm log_errx("fstat %s", filename); 303*819281eeSdp-arm 304*819281eeSdp-arm image = malloc(sizeof(*image)); 305*819281eeSdp-arm if (image == NULL) 306*819281eeSdp-arm log_err("malloc"); 307*819281eeSdp-arm 308*819281eeSdp-arm memcpy(&image->uuid, &toc_entry->uuid, sizeof(uuid_t)); 309*819281eeSdp-arm 310*819281eeSdp-arm image->buffer = malloc(st.st_size); 311*819281eeSdp-arm if (image->buffer == NULL) 312*819281eeSdp-arm log_err("malloc"); 313*819281eeSdp-arm if (fread(image->buffer, 1, st.st_size, fp) != st.st_size) 314*819281eeSdp-arm log_errx("Failed to read %s", filename); 315*819281eeSdp-arm image->size = st.st_size; 316*819281eeSdp-arm image->toc_entry = toc_entry; 317*819281eeSdp-arm 318*819281eeSdp-arm fclose(fp); 319*819281eeSdp-arm return image; 320*819281eeSdp-arm } 321*819281eeSdp-arm 322*819281eeSdp-arm static int write_image_to_file(image_t *image, char *filename) 323*819281eeSdp-arm { 324*819281eeSdp-arm FILE *fp; 325*819281eeSdp-arm 326*819281eeSdp-arm fp = fopen(filename, "w"); 327*819281eeSdp-arm if (fp == NULL) 328*819281eeSdp-arm log_err("fopen"); 329*819281eeSdp-arm if (fwrite(image->buffer, 1, image->size, fp) != image->size) 330*819281eeSdp-arm log_errx("Failed to write %s", filename); 331*819281eeSdp-arm fclose(fp); 332*819281eeSdp-arm return 0; 333*819281eeSdp-arm } 334*819281eeSdp-arm 335*819281eeSdp-arm static int fill_common_opts(struct option *opts, int has_arg) 336*819281eeSdp-arm { 337*819281eeSdp-arm int i; 338*819281eeSdp-arm 339*819281eeSdp-arm for (i = 0; toc_entries[i].cmdline_name != NULL; i++) { 340*819281eeSdp-arm opts[i].name = toc_entries[i].cmdline_name; 341*819281eeSdp-arm opts[i].has_arg = has_arg; 342*819281eeSdp-arm opts[i].flag = NULL; 343*819281eeSdp-arm opts[i].val = 0; 344*819281eeSdp-arm } 345*819281eeSdp-arm return i; 346*819281eeSdp-arm } 347*819281eeSdp-arm 348*819281eeSdp-arm static void add_opt(struct option *opts, int idx, char *name, 349*819281eeSdp-arm int has_arg, int val) 350*819281eeSdp-arm { 351*819281eeSdp-arm opts[idx].name = name; 352*819281eeSdp-arm opts[idx].has_arg = has_arg; 353*819281eeSdp-arm opts[idx].flag = NULL; 354*819281eeSdp-arm opts[idx].val = val; 355*819281eeSdp-arm } 356*819281eeSdp-arm 357*819281eeSdp-arm static int info_cmd(int argc, char *argv[]) 358*819281eeSdp-arm { 359*819281eeSdp-arm image_t *image; 360*819281eeSdp-arm uint64_t image_offset; 361*819281eeSdp-arm uint64_t image_size = 0; 362*819281eeSdp-arm fip_toc_header_t toc_header; 363*819281eeSdp-arm int i; 364*819281eeSdp-arm 365*819281eeSdp-arm if (argc != 2) 366*819281eeSdp-arm usage(); 367*819281eeSdp-arm argc--, argv++; 368*819281eeSdp-arm 369*819281eeSdp-arm parse_fip(argv[0], &toc_header); 370*819281eeSdp-arm 371*819281eeSdp-arm if (verbose) { 372*819281eeSdp-arm log_dbgx("toc_header[name]: 0x%llX", 373*819281eeSdp-arm (unsigned long long)toc_header.name); 374*819281eeSdp-arm log_dbgx("toc_header[serial_number]: 0x%llX", 375*819281eeSdp-arm (unsigned long long)toc_header.serial_number); 376*819281eeSdp-arm log_dbgx("toc_header[flags]: 0x%llX", 377*819281eeSdp-arm (unsigned long long)toc_header.flags); 378*819281eeSdp-arm } 379*819281eeSdp-arm 380*819281eeSdp-arm image_offset = sizeof(fip_toc_header_t) + 381*819281eeSdp-arm (sizeof(fip_toc_entry_t) * (nr_images + 1)); 382*819281eeSdp-arm 383*819281eeSdp-arm for (i = 0; i < nr_images; i++) { 384*819281eeSdp-arm image = images[i]; 385*819281eeSdp-arm if (image->toc_entry != NULL) 386*819281eeSdp-arm printf("%s: ", image->toc_entry->name); 387*819281eeSdp-arm else 388*819281eeSdp-arm printf("Unknown entry: "); 389*819281eeSdp-arm image_size = image->size; 390*819281eeSdp-arm printf("offset=0x%llX, size=0x%llX", 391*819281eeSdp-arm (unsigned long long)image_offset, 392*819281eeSdp-arm (unsigned long long)image_size); 393*819281eeSdp-arm if (image->toc_entry != NULL) 394*819281eeSdp-arm printf(", cmdline=\"--%s\"\n", 395*819281eeSdp-arm image->toc_entry->cmdline_name); 396*819281eeSdp-arm else 397*819281eeSdp-arm putchar('\n'); 398*819281eeSdp-arm image_offset += image_size; 399*819281eeSdp-arm } 400*819281eeSdp-arm 401*819281eeSdp-arm free_images(); 402*819281eeSdp-arm return 0; 403*819281eeSdp-arm } 404*819281eeSdp-arm 405*819281eeSdp-arm static void info_usage(void) 406*819281eeSdp-arm { 407*819281eeSdp-arm printf("fiptool info FIP_FILENAME\n"); 408*819281eeSdp-arm } 409*819281eeSdp-arm 410*819281eeSdp-arm static int pack_images(char *filename, uint64_t toc_flags) 411*819281eeSdp-arm { 412*819281eeSdp-arm FILE *fp; 413*819281eeSdp-arm image_t *image; 414*819281eeSdp-arm fip_toc_header_t *toc_header; 415*819281eeSdp-arm fip_toc_entry_t *toc_entry; 416*819281eeSdp-arm char *buf; 417*819281eeSdp-arm uint64_t entry_offset, buf_size, payload_size; 418*819281eeSdp-arm int i; 419*819281eeSdp-arm 420*819281eeSdp-arm /* Calculate total payload size and allocate scratch buffer. */ 421*819281eeSdp-arm payload_size = 0; 422*819281eeSdp-arm for (i = 0; i < nr_images; i++) 423*819281eeSdp-arm payload_size += images[i]->size; 424*819281eeSdp-arm 425*819281eeSdp-arm buf_size = sizeof(fip_toc_header_t) + 426*819281eeSdp-arm sizeof(fip_toc_entry_t) * (nr_images + 1); 427*819281eeSdp-arm buf = calloc(1, buf_size); 428*819281eeSdp-arm if (buf == NULL) 429*819281eeSdp-arm log_err("calloc"); 430*819281eeSdp-arm 431*819281eeSdp-arm /* Build up header and ToC entries from the image table. */ 432*819281eeSdp-arm toc_header = (fip_toc_header_t *)buf; 433*819281eeSdp-arm toc_header->name = TOC_HEADER_NAME; 434*819281eeSdp-arm toc_header->serial_number = TOC_HEADER_SERIAL_NUMBER; 435*819281eeSdp-arm toc_header->flags = toc_flags; 436*819281eeSdp-arm 437*819281eeSdp-arm toc_entry = (fip_toc_entry_t *)(toc_header + 1); 438*819281eeSdp-arm 439*819281eeSdp-arm entry_offset = buf_size; 440*819281eeSdp-arm for (i = 0; i < nr_images; i++) { 441*819281eeSdp-arm image = images[i]; 442*819281eeSdp-arm memcpy(&toc_entry->uuid, &image->uuid, sizeof(uuid_t)); 443*819281eeSdp-arm toc_entry->offset_address = entry_offset; 444*819281eeSdp-arm toc_entry->size = image->size; 445*819281eeSdp-arm toc_entry->flags = 0; 446*819281eeSdp-arm entry_offset += toc_entry->size; 447*819281eeSdp-arm toc_entry++; 448*819281eeSdp-arm } 449*819281eeSdp-arm 450*819281eeSdp-arm /* Append a null uuid entry to mark the end of ToC entries. */ 451*819281eeSdp-arm memcpy(&toc_entry->uuid, &uuid_null, sizeof(uuid_t)); 452*819281eeSdp-arm toc_entry->offset_address = entry_offset; 453*819281eeSdp-arm toc_entry->size = 0; 454*819281eeSdp-arm toc_entry->flags = 0; 455*819281eeSdp-arm 456*819281eeSdp-arm /* Generate the FIP file. */ 457*819281eeSdp-arm fp = fopen(filename, "w"); 458*819281eeSdp-arm if (fp == NULL) 459*819281eeSdp-arm log_err("fopen %s", filename); 460*819281eeSdp-arm 461*819281eeSdp-arm if (verbose) 462*819281eeSdp-arm log_dbgx("Metadata size: %zu bytes", buf_size); 463*819281eeSdp-arm 464*819281eeSdp-arm if (fwrite(buf, 1, buf_size, fp) != buf_size) 465*819281eeSdp-arm log_errx("Failed to write image to %s", filename); 466*819281eeSdp-arm free(buf); 467*819281eeSdp-arm 468*819281eeSdp-arm if (verbose) 469*819281eeSdp-arm log_dbgx("Payload size: %zu bytes", payload_size); 470*819281eeSdp-arm 471*819281eeSdp-arm for (i = 0; i < nr_images; i++) { 472*819281eeSdp-arm image = images[i]; 473*819281eeSdp-arm if (fwrite(image->buffer, 1, image->size, fp) != image->size) 474*819281eeSdp-arm log_errx("Failed to write image to %s", filename); 475*819281eeSdp-arm } 476*819281eeSdp-arm 477*819281eeSdp-arm fclose(fp); 478*819281eeSdp-arm return 0; 479*819281eeSdp-arm } 480*819281eeSdp-arm 481*819281eeSdp-arm /* 482*819281eeSdp-arm * This function is shared between the create and update subcommands. 483*819281eeSdp-arm * The difference between the two subcommands is that when the FIP file 484*819281eeSdp-arm * is created, the parsing of an existing FIP is skipped. This results 485*819281eeSdp-arm * in update_fip() creating the new FIP file from scratch because the 486*819281eeSdp-arm * internal image table is not populated. 487*819281eeSdp-arm */ 488*819281eeSdp-arm static void update_fip(void) 489*819281eeSdp-arm { 490*819281eeSdp-arm toc_entry_t *toc_entry; 491*819281eeSdp-arm image_t *image; 492*819281eeSdp-arm 493*819281eeSdp-arm /* Add or replace images in the FIP file. */ 494*819281eeSdp-arm for (toc_entry = toc_entries; 495*819281eeSdp-arm toc_entry->cmdline_name != NULL; 496*819281eeSdp-arm toc_entry++) { 497*819281eeSdp-arm if (toc_entry->action != DO_PACK) 498*819281eeSdp-arm continue; 499*819281eeSdp-arm 500*819281eeSdp-arm image = read_image_from_file(toc_entry, toc_entry->action_arg); 501*819281eeSdp-arm if (toc_entry->image != NULL) { 502*819281eeSdp-arm if (verbose) 503*819281eeSdp-arm log_dbgx("Replacing image %s.bin with %s", 504*819281eeSdp-arm toc_entry->cmdline_name, 505*819281eeSdp-arm toc_entry->action_arg); 506*819281eeSdp-arm replace_image(toc_entry->image, image); 507*819281eeSdp-arm } else { 508*819281eeSdp-arm if (verbose) 509*819281eeSdp-arm log_dbgx("Adding image %s", 510*819281eeSdp-arm toc_entry->action_arg); 511*819281eeSdp-arm add_image(image); 512*819281eeSdp-arm } 513*819281eeSdp-arm /* Link backpointer from lookup entry. */ 514*819281eeSdp-arm toc_entry->image = image; 515*819281eeSdp-arm 516*819281eeSdp-arm free(toc_entry->action_arg); 517*819281eeSdp-arm toc_entry->action_arg = NULL; 518*819281eeSdp-arm } 519*819281eeSdp-arm } 520*819281eeSdp-arm 521*819281eeSdp-arm static void parse_plat_toc_flags(char *arg, unsigned long long *toc_flags) 522*819281eeSdp-arm { 523*819281eeSdp-arm unsigned long long flags; 524*819281eeSdp-arm char *endptr; 525*819281eeSdp-arm 526*819281eeSdp-arm errno = 0; 527*819281eeSdp-arm flags = strtoull(arg, &endptr, 16); 528*819281eeSdp-arm if (*endptr != '\0' || flags > UINT16_MAX || errno != 0) 529*819281eeSdp-arm log_errx("Invalid platform ToC flags: %s", arg); 530*819281eeSdp-arm /* Platform ToC flags is a 16-bit field occupying bits [32-47]. */ 531*819281eeSdp-arm *toc_flags |= flags << 32; 532*819281eeSdp-arm } 533*819281eeSdp-arm 534*819281eeSdp-arm static int create_cmd(int argc, char *argv[]) 535*819281eeSdp-arm { 536*819281eeSdp-arm struct option opts[toc_entries_len + 1]; 537*819281eeSdp-arm unsigned long long toc_flags = 0; 538*819281eeSdp-arm int i; 539*819281eeSdp-arm 540*819281eeSdp-arm if (argc < 2) 541*819281eeSdp-arm usage(); 542*819281eeSdp-arm 543*819281eeSdp-arm i = fill_common_opts(opts, required_argument); 544*819281eeSdp-arm add_opt(opts, i, "plat-toc-flags", required_argument, 545*819281eeSdp-arm OPT_PLAT_TOC_FLAGS); 546*819281eeSdp-arm add_opt(opts, ++i, NULL, 0, 0); 547*819281eeSdp-arm 548*819281eeSdp-arm while (1) { 549*819281eeSdp-arm int c, opt_index; 550*819281eeSdp-arm 551*819281eeSdp-arm c = getopt_long(argc, argv, "o:", opts, &opt_index); 552*819281eeSdp-arm if (c == -1) 553*819281eeSdp-arm break; 554*819281eeSdp-arm 555*819281eeSdp-arm switch (c) { 556*819281eeSdp-arm case OPT_TOC_ENTRY: { 557*819281eeSdp-arm toc_entry_t *toc_entry; 558*819281eeSdp-arm 559*819281eeSdp-arm toc_entry = &toc_entries[opt_index]; 560*819281eeSdp-arm toc_entry->action = DO_PACK; 561*819281eeSdp-arm toc_entry->action_arg = strdup(optarg); 562*819281eeSdp-arm if (toc_entry->action_arg == NULL) 563*819281eeSdp-arm log_err("strdup"); 564*819281eeSdp-arm break; 565*819281eeSdp-arm } 566*819281eeSdp-arm case OPT_PLAT_TOC_FLAGS: 567*819281eeSdp-arm parse_plat_toc_flags(optarg, &toc_flags); 568*819281eeSdp-arm break; 569*819281eeSdp-arm default: 570*819281eeSdp-arm usage(); 571*819281eeSdp-arm } 572*819281eeSdp-arm } 573*819281eeSdp-arm argc -= optind; 574*819281eeSdp-arm argv += optind; 575*819281eeSdp-arm 576*819281eeSdp-arm if (argc == 0) 577*819281eeSdp-arm usage(); 578*819281eeSdp-arm 579*819281eeSdp-arm update_fip(); 580*819281eeSdp-arm 581*819281eeSdp-arm pack_images(argv[0], toc_flags); 582*819281eeSdp-arm free_images(); 583*819281eeSdp-arm return 0; 584*819281eeSdp-arm } 585*819281eeSdp-arm 586*819281eeSdp-arm static void create_usage(void) 587*819281eeSdp-arm { 588*819281eeSdp-arm toc_entry_t *toc_entry = toc_entries; 589*819281eeSdp-arm 590*819281eeSdp-arm printf("fiptfool create [--plat-toc-flags <value>] [opts] FIP_FILENAME\n"); 591*819281eeSdp-arm printf(" --plat-toc-flags <value>\t16-bit platform specific flag field " 592*819281eeSdp-arm "occupying bits 32-47 in 64-bit ToC header.\n"); 593*819281eeSdp-arm fputc('\n', stderr); 594*819281eeSdp-arm printf("Specific images are packed with the following options:\n"); 595*819281eeSdp-arm for (; toc_entry->cmdline_name != NULL; toc_entry++) 596*819281eeSdp-arm printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, 597*819281eeSdp-arm toc_entry->name); 598*819281eeSdp-arm } 599*819281eeSdp-arm 600*819281eeSdp-arm static int update_cmd(int argc, char *argv[]) 601*819281eeSdp-arm { 602*819281eeSdp-arm struct option opts[toc_entries_len + 2]; 603*819281eeSdp-arm char outfile[FILENAME_MAX] = { 0 }; 604*819281eeSdp-arm fip_toc_header_t toc_header = { 0 }; 605*819281eeSdp-arm unsigned long long toc_flags = 0; 606*819281eeSdp-arm int pflag = 0; 607*819281eeSdp-arm int i; 608*819281eeSdp-arm 609*819281eeSdp-arm if (argc < 2) 610*819281eeSdp-arm usage(); 611*819281eeSdp-arm 612*819281eeSdp-arm i = fill_common_opts(opts, required_argument); 613*819281eeSdp-arm add_opt(opts, i, "out", required_argument, 'o'); 614*819281eeSdp-arm add_opt(opts, ++i, "plat-toc-flags", required_argument, 615*819281eeSdp-arm OPT_PLAT_TOC_FLAGS); 616*819281eeSdp-arm add_opt(opts, ++i, NULL, 0, 0); 617*819281eeSdp-arm 618*819281eeSdp-arm while (1) { 619*819281eeSdp-arm int c, opt_index; 620*819281eeSdp-arm 621*819281eeSdp-arm c = getopt_long(argc, argv, "o:", opts, &opt_index); 622*819281eeSdp-arm if (c == -1) 623*819281eeSdp-arm break; 624*819281eeSdp-arm 625*819281eeSdp-arm switch (c) { 626*819281eeSdp-arm case OPT_TOC_ENTRY: { 627*819281eeSdp-arm toc_entry_t *toc_entry; 628*819281eeSdp-arm 629*819281eeSdp-arm toc_entry = &toc_entries[opt_index]; 630*819281eeSdp-arm toc_entry->action = DO_PACK; 631*819281eeSdp-arm toc_entry->action_arg = strdup(optarg); 632*819281eeSdp-arm if (toc_entry->action_arg == NULL) 633*819281eeSdp-arm log_err("strdup"); 634*819281eeSdp-arm break; 635*819281eeSdp-arm } 636*819281eeSdp-arm case OPT_PLAT_TOC_FLAGS: { 637*819281eeSdp-arm parse_plat_toc_flags(optarg, &toc_flags); 638*819281eeSdp-arm pflag = 1; 639*819281eeSdp-arm break; 640*819281eeSdp-arm } 641*819281eeSdp-arm case 'o': 642*819281eeSdp-arm snprintf(outfile, sizeof(outfile), "%s", optarg); 643*819281eeSdp-arm break; 644*819281eeSdp-arm default: 645*819281eeSdp-arm usage(); 646*819281eeSdp-arm } 647*819281eeSdp-arm } 648*819281eeSdp-arm argc -= optind; 649*819281eeSdp-arm argv += optind; 650*819281eeSdp-arm 651*819281eeSdp-arm if (argc == 0) 652*819281eeSdp-arm usage(); 653*819281eeSdp-arm 654*819281eeSdp-arm if (outfile[0] == '\0') 655*819281eeSdp-arm snprintf(outfile, sizeof(outfile), "%s", argv[0]); 656*819281eeSdp-arm 657*819281eeSdp-arm if (access(outfile, F_OK) == 0) 658*819281eeSdp-arm parse_fip(argv[0], &toc_header); 659*819281eeSdp-arm 660*819281eeSdp-arm if (pflag) 661*819281eeSdp-arm toc_header.flags &= ~(0xffffULL << 32); 662*819281eeSdp-arm toc_flags = (toc_header.flags |= toc_flags); 663*819281eeSdp-arm 664*819281eeSdp-arm update_fip(); 665*819281eeSdp-arm 666*819281eeSdp-arm pack_images(outfile, toc_flags); 667*819281eeSdp-arm free_images(); 668*819281eeSdp-arm return 0; 669*819281eeSdp-arm } 670*819281eeSdp-arm 671*819281eeSdp-arm static void update_usage(void) 672*819281eeSdp-arm { 673*819281eeSdp-arm toc_entry_t *toc_entry = toc_entries; 674*819281eeSdp-arm 675*819281eeSdp-arm printf("fiptfool update [--out FIP_FILENAME] " 676*819281eeSdp-arm "[--plat-toc-flags <value>] [opts] FIP_FILENAME\n"); 677*819281eeSdp-arm printf(" --out FIP_FILENAME\t\tSet an alternative output FIP file.\n"); 678*819281eeSdp-arm printf(" --plat-toc-flags <value>\t16-bit platform specific flag field " 679*819281eeSdp-arm "occupying bits 32-47 in 64-bit ToC header.\n"); 680*819281eeSdp-arm fputc('\n', stderr); 681*819281eeSdp-arm printf("Specific images are packed with the following options:\n"); 682*819281eeSdp-arm for (; toc_entry->cmdline_name != NULL; toc_entry++) 683*819281eeSdp-arm printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, 684*819281eeSdp-arm toc_entry->name); 685*819281eeSdp-arm } 686*819281eeSdp-arm 687*819281eeSdp-arm static int unpack_cmd(int argc, char *argv[]) 688*819281eeSdp-arm { 689*819281eeSdp-arm struct option opts[toc_entries_len + 3]; 690*819281eeSdp-arm char file[FILENAME_MAX], outdir[PATH_MAX] = { 0 }; 691*819281eeSdp-arm toc_entry_t *toc_entry; 692*819281eeSdp-arm int fflag = 0; 693*819281eeSdp-arm int unpack_all = 1; 694*819281eeSdp-arm int i; 695*819281eeSdp-arm 696*819281eeSdp-arm if (argc < 2) 697*819281eeSdp-arm usage(); 698*819281eeSdp-arm 699*819281eeSdp-arm i = fill_common_opts(opts, required_argument); 700*819281eeSdp-arm add_opt(opts, i, "force", no_argument, 'f'); 701*819281eeSdp-arm add_opt(opts, ++i, "out", required_argument, 'o'); 702*819281eeSdp-arm add_opt(opts, ++i, NULL, 0, 0); 703*819281eeSdp-arm 704*819281eeSdp-arm while (1) { 705*819281eeSdp-arm int c, opt_index; 706*819281eeSdp-arm 707*819281eeSdp-arm c = getopt_long(argc, argv, "fo:", opts, &opt_index); 708*819281eeSdp-arm if (c == -1) 709*819281eeSdp-arm break; 710*819281eeSdp-arm 711*819281eeSdp-arm switch (c) { 712*819281eeSdp-arm case OPT_TOC_ENTRY: 713*819281eeSdp-arm unpack_all = 0; 714*819281eeSdp-arm toc_entry = &toc_entries[opt_index]; 715*819281eeSdp-arm toc_entry->action = DO_UNPACK; 716*819281eeSdp-arm toc_entry->action_arg = strdup(optarg); 717*819281eeSdp-arm if (toc_entry->action_arg == NULL) 718*819281eeSdp-arm log_err("strdup"); 719*819281eeSdp-arm break; 720*819281eeSdp-arm case 'f': 721*819281eeSdp-arm fflag = 1; 722*819281eeSdp-arm break; 723*819281eeSdp-arm case 'o': 724*819281eeSdp-arm snprintf(outdir, sizeof(outdir), "%s", optarg); 725*819281eeSdp-arm break; 726*819281eeSdp-arm default: 727*819281eeSdp-arm usage(); 728*819281eeSdp-arm } 729*819281eeSdp-arm } 730*819281eeSdp-arm argc -= optind; 731*819281eeSdp-arm argv += optind; 732*819281eeSdp-arm 733*819281eeSdp-arm if (argc == 0) 734*819281eeSdp-arm usage(); 735*819281eeSdp-arm 736*819281eeSdp-arm parse_fip(argv[0], NULL); 737*819281eeSdp-arm 738*819281eeSdp-arm if (outdir[0] != '\0') 739*819281eeSdp-arm if (chdir(outdir) == -1) 740*819281eeSdp-arm log_err("chdir %s", outdir); 741*819281eeSdp-arm 742*819281eeSdp-arm /* Mark all images to be unpacked. */ 743*819281eeSdp-arm if (unpack_all) { 744*819281eeSdp-arm for (toc_entry = toc_entries; 745*819281eeSdp-arm toc_entry->cmdline_name != NULL; 746*819281eeSdp-arm toc_entry++) { 747*819281eeSdp-arm if (toc_entry->image != NULL) { 748*819281eeSdp-arm toc_entry->action = DO_UNPACK; 749*819281eeSdp-arm toc_entry->action_arg = NULL; 750*819281eeSdp-arm } 751*819281eeSdp-arm } 752*819281eeSdp-arm } 753*819281eeSdp-arm 754*819281eeSdp-arm /* Unpack all specified images. */ 755*819281eeSdp-arm for (toc_entry = toc_entries; 756*819281eeSdp-arm toc_entry->cmdline_name != NULL; 757*819281eeSdp-arm toc_entry++) { 758*819281eeSdp-arm if (toc_entry->action != DO_UNPACK) 759*819281eeSdp-arm continue; 760*819281eeSdp-arm 761*819281eeSdp-arm /* Build filename. */ 762*819281eeSdp-arm if (toc_entry->action_arg == NULL) 763*819281eeSdp-arm snprintf(file, sizeof(file), "%s.bin", 764*819281eeSdp-arm toc_entry->cmdline_name); 765*819281eeSdp-arm else 766*819281eeSdp-arm snprintf(file, sizeof(file), "%s", 767*819281eeSdp-arm toc_entry->action_arg); 768*819281eeSdp-arm 769*819281eeSdp-arm if (toc_entry->image == NULL) { 770*819281eeSdp-arm log_warnx("Requested image %s is not in %s", 771*819281eeSdp-arm file, argv[0]); 772*819281eeSdp-arm free(toc_entry->action_arg); 773*819281eeSdp-arm toc_entry->action_arg = NULL; 774*819281eeSdp-arm continue; 775*819281eeSdp-arm } 776*819281eeSdp-arm 777*819281eeSdp-arm if (access(file, F_OK) != 0 || fflag) { 778*819281eeSdp-arm if (verbose) 779*819281eeSdp-arm log_dbgx("Unpacking %s", file); 780*819281eeSdp-arm write_image_to_file(toc_entry->image, file); 781*819281eeSdp-arm } else { 782*819281eeSdp-arm log_warnx("File %s already exists, use --force to overwrite it", 783*819281eeSdp-arm file); 784*819281eeSdp-arm } 785*819281eeSdp-arm 786*819281eeSdp-arm free(toc_entry->action_arg); 787*819281eeSdp-arm toc_entry->action_arg = NULL; 788*819281eeSdp-arm } 789*819281eeSdp-arm 790*819281eeSdp-arm free_images(); 791*819281eeSdp-arm return 0; 792*819281eeSdp-arm } 793*819281eeSdp-arm 794*819281eeSdp-arm static void unpack_usage(void) 795*819281eeSdp-arm { 796*819281eeSdp-arm toc_entry_t *toc_entry = toc_entries; 797*819281eeSdp-arm 798*819281eeSdp-arm printf("fiptool unpack [--force] [--out <path>] [opts] FIP_FILENAME\n"); 799*819281eeSdp-arm printf(" --force\tIf the output file already exists, use --force to " 800*819281eeSdp-arm "overwrite it.\n"); 801*819281eeSdp-arm printf(" --out path\tSet the output directory path.\n"); 802*819281eeSdp-arm fputc('\n', stderr); 803*819281eeSdp-arm printf("Specific images are unpacked with the following options:\n"); 804*819281eeSdp-arm for (; toc_entry->cmdline_name != NULL; toc_entry++) 805*819281eeSdp-arm printf(" --%-16s FILENAME\t%s\n", toc_entry->cmdline_name, 806*819281eeSdp-arm toc_entry->name); 807*819281eeSdp-arm fputc('\n', stderr); 808*819281eeSdp-arm printf("If no options are provided, all images will be unpacked.\n"); 809*819281eeSdp-arm } 810*819281eeSdp-arm 811*819281eeSdp-arm static int remove_cmd(int argc, char *argv[]) 812*819281eeSdp-arm { 813*819281eeSdp-arm struct option opts[toc_entries_len + 2]; 814*819281eeSdp-arm char outfile[FILENAME_MAX] = { 0 }; 815*819281eeSdp-arm fip_toc_header_t toc_header; 816*819281eeSdp-arm toc_entry_t *toc_entry; 817*819281eeSdp-arm int fflag = 0; 818*819281eeSdp-arm int i; 819*819281eeSdp-arm 820*819281eeSdp-arm if (argc < 2) 821*819281eeSdp-arm usage(); 822*819281eeSdp-arm 823*819281eeSdp-arm i = fill_common_opts(opts, no_argument); 824*819281eeSdp-arm add_opt(opts, i, "force", no_argument, 'f'); 825*819281eeSdp-arm add_opt(opts, ++i, "out", required_argument, 'o'); 826*819281eeSdp-arm add_opt(opts, ++i, NULL, 0, 0); 827*819281eeSdp-arm 828*819281eeSdp-arm while (1) { 829*819281eeSdp-arm int c, opt_index; 830*819281eeSdp-arm 831*819281eeSdp-arm c = getopt_long(argc, argv, "fo:", opts, &opt_index); 832*819281eeSdp-arm if (c == -1) 833*819281eeSdp-arm break; 834*819281eeSdp-arm 835*819281eeSdp-arm switch (c) { 836*819281eeSdp-arm case OPT_TOC_ENTRY: 837*819281eeSdp-arm toc_entry = &toc_entries[opt_index]; 838*819281eeSdp-arm toc_entry->action = DO_REMOVE; 839*819281eeSdp-arm break; 840*819281eeSdp-arm case 'f': 841*819281eeSdp-arm fflag = 1; 842*819281eeSdp-arm break; 843*819281eeSdp-arm case 'o': 844*819281eeSdp-arm snprintf(outfile, sizeof(outfile), "%s", optarg); 845*819281eeSdp-arm break; 846*819281eeSdp-arm default: 847*819281eeSdp-arm usage(); 848*819281eeSdp-arm } 849*819281eeSdp-arm } 850*819281eeSdp-arm argc -= optind; 851*819281eeSdp-arm argv += optind; 852*819281eeSdp-arm 853*819281eeSdp-arm if (argc == 0) 854*819281eeSdp-arm usage(); 855*819281eeSdp-arm 856*819281eeSdp-arm if (outfile[0] != '\0' && access(outfile, F_OK) == 0 && !fflag) 857*819281eeSdp-arm log_errx("File %s already exists, use --force to overwrite it", 858*819281eeSdp-arm outfile); 859*819281eeSdp-arm 860*819281eeSdp-arm if (outfile[0] == '\0') 861*819281eeSdp-arm snprintf(outfile, sizeof(outfile), "%s", argv[0]); 862*819281eeSdp-arm 863*819281eeSdp-arm parse_fip(argv[0], &toc_header); 864*819281eeSdp-arm 865*819281eeSdp-arm for (toc_entry = toc_entries; 866*819281eeSdp-arm toc_entry->cmdline_name != NULL; 867*819281eeSdp-arm toc_entry++) { 868*819281eeSdp-arm if (toc_entry->action != DO_REMOVE) 869*819281eeSdp-arm continue; 870*819281eeSdp-arm if (toc_entry->image != NULL) { 871*819281eeSdp-arm if (verbose) 872*819281eeSdp-arm log_dbgx("Removing %s.bin", 873*819281eeSdp-arm toc_entry->cmdline_name); 874*819281eeSdp-arm remove_image(toc_entry->image); 875*819281eeSdp-arm } else { 876*819281eeSdp-arm log_warnx("Requested image %s.bin is not in %s", 877*819281eeSdp-arm toc_entry->cmdline_name, argv[0]); 878*819281eeSdp-arm } 879*819281eeSdp-arm } 880*819281eeSdp-arm 881*819281eeSdp-arm pack_images(outfile, toc_header.flags); 882*819281eeSdp-arm free_images(); 883*819281eeSdp-arm return 0; 884*819281eeSdp-arm } 885*819281eeSdp-arm 886*819281eeSdp-arm static void remove_usage(void) 887*819281eeSdp-arm { 888*819281eeSdp-arm toc_entry_t *toc_entry = toc_entries; 889*819281eeSdp-arm 890*819281eeSdp-arm printf("fiptool remove [--force] [--out FIP_FILENAME] [opts] FIP_FILENAME\n"); 891*819281eeSdp-arm printf(" --force\t\tIf the output FIP file already exists, use --force to " 892*819281eeSdp-arm "overwrite it.\n"); 893*819281eeSdp-arm printf(" --out FIP_FILENAME\tSet an alternative output FIP file.\n"); 894*819281eeSdp-arm fputc('\n', stderr); 895*819281eeSdp-arm printf("Specific images are removed with the following options:\n"); 896*819281eeSdp-arm for (; toc_entry->cmdline_name != NULL; toc_entry++) 897*819281eeSdp-arm printf(" --%-16s\t%s\n", toc_entry->cmdline_name, 898*819281eeSdp-arm toc_entry->name); 899*819281eeSdp-arm } 900*819281eeSdp-arm 901*819281eeSdp-arm static int version_cmd(int argc, char *argv[]) 902*819281eeSdp-arm { 903*819281eeSdp-arm #ifdef VERSION 904*819281eeSdp-arm puts(VERSION); 905*819281eeSdp-arm #else 906*819281eeSdp-arm /* If built from fiptool directory, VERSION is not set. */ 907*819281eeSdp-arm puts("Unknown version"); 908*819281eeSdp-arm #endif 909*819281eeSdp-arm return 0; 910*819281eeSdp-arm } 911*819281eeSdp-arm 912*819281eeSdp-arm static void version_usage(void) 913*819281eeSdp-arm { 914*819281eeSdp-arm printf("fiptool version\n"); 915*819281eeSdp-arm } 916*819281eeSdp-arm 917*819281eeSdp-arm static int help_cmd(int argc, char *argv[]) 918*819281eeSdp-arm { 919*819281eeSdp-arm int i; 920*819281eeSdp-arm 921*819281eeSdp-arm if (argc < 2) 922*819281eeSdp-arm usage(); 923*819281eeSdp-arm argc--, argv++; 924*819281eeSdp-arm 925*819281eeSdp-arm for (i = 0; i < NELEM(cmds); i++) { 926*819281eeSdp-arm if (strcmp(cmds[i].name, argv[0]) == 0 && 927*819281eeSdp-arm cmds[i].usage != NULL) { 928*819281eeSdp-arm cmds[i].usage(); 929*819281eeSdp-arm break; 930*819281eeSdp-arm } 931*819281eeSdp-arm } 932*819281eeSdp-arm if (i == NELEM(cmds)) 933*819281eeSdp-arm printf("No help for subcommand '%s'\n", argv[0]); 934*819281eeSdp-arm return 0; 935*819281eeSdp-arm } 936*819281eeSdp-arm 937*819281eeSdp-arm static void usage(void) 938*819281eeSdp-arm { 939*819281eeSdp-arm printf("usage: [--verbose] fiptool <command> [<args>]\n"); 940*819281eeSdp-arm printf("Global options supported:\n"); 941*819281eeSdp-arm printf(" --verbose\tEnable verbose output for all commands.\n"); 942*819281eeSdp-arm fputc('\n', stderr); 943*819281eeSdp-arm printf("Commands supported:\n"); 944*819281eeSdp-arm printf(" info\t\tList images contained in FIP.\n"); 945*819281eeSdp-arm printf(" create\tCreate a new FIP with the given images.\n"); 946*819281eeSdp-arm printf(" update\tUpdate an existing FIP with the given images.\n"); 947*819281eeSdp-arm printf(" unpack\tUnpack images from FIP.\n"); 948*819281eeSdp-arm printf(" remove\tRemove images from FIP.\n"); 949*819281eeSdp-arm printf(" version\tShow fiptool version.\n"); 950*819281eeSdp-arm printf(" help\t\tShow help for given command.\n"); 951*819281eeSdp-arm exit(1); 952*819281eeSdp-arm } 953*819281eeSdp-arm 954*819281eeSdp-arm int main(int argc, char *argv[]) 955*819281eeSdp-arm { 956*819281eeSdp-arm int i, ret = 0; 957*819281eeSdp-arm 958*819281eeSdp-arm if (argc < 2) 959*819281eeSdp-arm usage(); 960*819281eeSdp-arm argc--, argv++; 961*819281eeSdp-arm 962*819281eeSdp-arm if (strcmp(argv[0], "-v") == 0 || 963*819281eeSdp-arm strcmp(argv[0], "--verbose") == 0) { 964*819281eeSdp-arm verbose = 1; 965*819281eeSdp-arm argc--, argv++; 966*819281eeSdp-arm } 967*819281eeSdp-arm 968*819281eeSdp-arm for (i = 0; i < NELEM(cmds); i++) { 969*819281eeSdp-arm if (strcmp(cmds[i].name, argv[0]) == 0) { 970*819281eeSdp-arm ret = cmds[i].handler(argc, argv); 971*819281eeSdp-arm break; 972*819281eeSdp-arm } 973*819281eeSdp-arm } 974*819281eeSdp-arm if (i == NELEM(cmds)) 975*819281eeSdp-arm usage(); 976*819281eeSdp-arm return ret; 977*819281eeSdp-arm } 978