uboot/tools/ifwitool.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * ifwitool, CLI utility for Integrated Firmware Image (IFWI) manipulation
   4 *
   5 * This is taken from the Coreboot project
   6 */
   7
   8#include <assert.h>
   9#include <stdbool.h>
  10#include <getopt.h>
  11#include "imagetool.h"
  12#include "os_support.h"
  13
  14#ifndef __packed
  15#define __packed                __attribute__((packed))
  16#endif
  17#define KiB                     1024
  18
  19/*
  20 * min()/max()/clamp() macros that also do
  21 * strict type-checking.. See the
  22 * "unnecessary" pointer comparison.
  23 */
  24#define min(x, y) ({                            \
  25        typeof(x) _min1 = (x);                  \
  26        typeof(y) _min2 = (y);                  \
  27        (void)&_min1 == &_min2);                \
  28        _min1 < _min2 ? _min1 : _min2; })
  29
  30#define max(x, y) ({                            \
  31        typeof(x) _max1 = (x);                  \
  32        typeof(y) _max2 = (y);                  \
  33        (void)(&_max1 == &_max2);               \
  34        _max1 > _max2 ? _max1 : _max2; })
  35
  36static int verbose = 1;
  37
  38/* Buffer and file I/O */
  39struct buffer {
  40        char *name;
  41        char *data;
  42        size_t offset;
  43        size_t size;
  44};
  45
  46#define ERROR(...) { fprintf(stderr, "E: " __VA_ARGS__); }
  47#define INFO(...) { if (verbose > 0) fprintf(stderr, "INFO: " __VA_ARGS__); }
  48#define DEBUG(...) { if (verbose > 1) fprintf(stderr, "DEBUG: " __VA_ARGS__); }
  49
  50/*
  51 * BPDT is Boot Partition Descriptor Table. It is located at the start of a
  52 * logical boot partition(LBP). It stores information about the critical
  53 * sub-partitions present within the LBP.
  54 *
  55 * S-BPDT is Secondary Boot Partition Descriptor Table. It is located after the
  56 * critical sub-partitions and contains information about the non-critical
  57 * sub-partitions present within the LBP.
  58 *
  59 * Both tables are identified by BPDT_SIGNATURE stored at the start of the
  60 * table.
  61 */
  62#define BPDT_SIGNATURE                          (0x000055AA)
  63
  64/* Parameters passed in by caller */
  65static struct param {
  66        const char *file_name;
  67        const char *subpart_name;
  68        const char *image_name;
  69        bool dir_ops;
  70        const char *dentry_name;
  71} param;
  72
  73struct bpdt_header {
  74        /*
  75         * This is used to identify start of BPDT. It should always be
  76         * BPDT_SIGNATURE.
  77         */
  78        uint32_t signature;
  79        /* Count of BPDT entries present */
  80        uint16_t descriptor_count;
  81        /* Version - Currently supported = 1 */
  82        uint16_t bpdt_version;
  83        /* Unused - Should be 0 */
  84        uint32_t xor_redundant_block;
  85        /* Version of IFWI build */
  86        uint32_t ifwi_version;
  87        /* Version of FIT tool used to create IFWI */
  88        uint64_t fit_tool_version;
  89} __packed;
  90#define BPDT_HEADER_SIZE                        (sizeof(struct bpdt_header))
  91
  92struct bpdt_entry {
  93        /* Type of sub-partition */
  94        uint16_t type;
  95        /* Attributes of sub-partition */
  96        uint16_t flags;
  97        /* Offset of sub-partition from beginning of LBP */
  98        uint32_t offset;
  99        /* Size in bytes of sub-partition */
 100        uint32_t size;
 101} __packed;
 102#define BPDT_ENTRY_SIZE                 (sizeof(struct bpdt_entry))
 103
 104struct bpdt {
 105        struct bpdt_header h;
 106        /* In practice, this could be an array of 0 to n entries */
 107        struct bpdt_entry e[0];
 108} __packed;
 109
 110static inline size_t get_bpdt_size(struct bpdt_header *h)
 111{
 112        return (sizeof(*h) + BPDT_ENTRY_SIZE * h->descriptor_count);
 113}
 114
 115/* Minimum size in bytes allocated to BPDT in IFWI */
 116#define BPDT_MIN_SIZE                   ((size_t)512)
 117
 118/* Header to define directory header for sub-partition */
 119struct subpart_dir_header {
 120        /* Should be SUBPART_DIR_MARKER */
 121        uint32_t marker;
 122        /* Number of directory entries in the sub-partition */
 123        uint32_t num_entries;
 124        /* Currenty supported - 1 */
 125        uint8_t header_version;
 126        /* Currenty supported - 1 */
 127        uint8_t entry_version;
 128        /* Length of directory header in bytes */
 129        uint8_t header_length;
 130        /*
 131         * 2s complement of 8-bit sum from first byte of header to last byte of
 132         * last directory entry.
 133         */
 134        uint8_t checksum;
 135        /* ASCII short name of sub-partition */
 136        uint8_t name[4];
 137} __packed;
 138#define SUBPART_DIR_HEADER_SIZE                 \
 139                                        (sizeof(struct subpart_dir_header))
 140#define SUBPART_DIR_MARKER                              0x44504324
 141#define SUBPART_DIR_HEADER_VERSION_SUPPORTED    1
 142#define SUBPART_DIR_ENTRY_VERSION_SUPPORTED     1
 143
 144/* Structure for each directory entry for sub-partition */
 145struct subpart_dir_entry {
 146        /* Name of directory entry - Not guaranteed to be NULL-terminated */
 147        uint8_t name[12];
 148        /* Offset of entry from beginning of sub-partition */
 149        uint32_t offset;
 150        /* Length in bytes of sub-directory entry */
 151        uint32_t length;
 152        /* Must be zero */
 153        uint32_t rsvd;
 154} __packed;
 155#define SUBPART_DIR_ENTRY_SIZE                  \
 156                                        (sizeof(struct subpart_dir_entry))
 157
 158struct subpart_dir {
 159        struct subpart_dir_header h;
 160        /* In practice, this could be an array of 0 to n entries */
 161        struct subpart_dir_entry e[0];
 162} __packed;
 163
 164static inline size_t subpart_dir_size(struct subpart_dir_header *h)
 165{
 166        return (sizeof(*h) + SUBPART_DIR_ENTRY_SIZE * h->num_entries);
 167}
 168
 169struct manifest_header {
 170        uint32_t header_type;
 171        uint32_t header_length;
 172        uint32_t header_version;
 173        uint32_t flags;
 174        uint32_t vendor;
 175        uint32_t date;
 176        uint32_t size;
 177        uint32_t id;
 178        uint32_t rsvd;
 179        uint64_t version;
 180        uint32_t svn;
 181        uint64_t rsvd1;
 182        uint8_t rsvd2[64];
 183        uint32_t modulus_size;
 184        uint32_t exponent_size;
 185        uint8_t public_key[256];
 186        uint32_t exponent;
 187        uint8_t signature[256];
 188} __packed;
 189
 190#define DWORD_SIZE                              4
 191#define MANIFEST_HDR_SIZE                       (sizeof(struct manifest_header))
 192#define MANIFEST_ID_MAGIC                       (0x324e4d24)
 193
 194struct module {
 195        uint8_t name[12];
 196        uint8_t type;
 197        uint8_t hash_alg;
 198        uint16_t hash_size;
 199        uint32_t metadata_size;
 200        uint8_t metadata_hash[32];
 201} __packed;
 202
 203#define MODULE_SIZE                             (sizeof(struct module))
 204
 205struct signed_pkg_info_ext {
 206        uint32_t ext_type;
 207        uint32_t ext_length;
 208        uint8_t name[4];
 209        uint32_t vcn;
 210        uint8_t bitmap[16];
 211        uint32_t svn;
 212        uint8_t rsvd[16];
 213} __packed;
 214
 215#define SIGNED_PKG_INFO_EXT_TYPE                0x15
 216#define SIGNED_PKG_INFO_EXT_SIZE                \
 217        (sizeof(struct signed_pkg_info_ext))
 218
 219/*
 220 * Attributes for various IFWI sub-partitions.
 221 * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
 222 * BPDT.
 223 * NON_CRITICAL_SUBPART = Sub-Partition entry should be present in S-BPDT.
 224 * CONTAINS_DIR = Sub-Partition contains directory.
 225 * AUTO_GENERATED = Sub-Partition is generated by the tool.
 226 * MANDATORY_BPDT_ENTRY = Even if sub-partition is deleted, BPDT should contain
 227 * an entry for it with size 0 and offset 0.
 228 */
 229enum subpart_attributes {
 230        LIES_WITHIN_BPDT_4K = (1 << 0),
 231        NON_CRITICAL_SUBPART = (1 << 1),
 232        CONTAINS_DIR = (1 << 2),
 233        AUTO_GENERATED = (1 << 3),
 234        MANDATORY_BPDT_ENTRY = (1 << 4),
 235};
 236
 237/* Type value for various IFWI sub-partitions */
 238enum bpdt_entry_type {
 239        SMIP_TYPE               = 0,
 240        CSE_RBE_TYPE            = 1,
 241        CSE_BUP_TYPE            = 2,
 242        UCODE_TYPE              = 3,
 243        IBB_TYPE                = 4,
 244        S_BPDT_TYPE             = 5,
 245        OBB_TYPE                = 6,
 246        CSE_MAIN_TYPE           = 7,
 247        ISH_TYPE                = 8,
 248        CSE_IDLM_TYPE           = 9,
 249        IFP_OVERRIDE_TYPE       = 10,
 250        DEBUG_TOKENS_TYPE       = 11,
 251        UFS_PHY_TYPE            = 12,
 252        UFS_GPP_TYPE            = 13,
 253        PMC_TYPE                = 14,
 254        IUNIT_TYPE              = 15,
 255        NVM_CONFIG_TYPE = 16,
 256        UEP_TYPE                = 17,
 257        UFS_RATE_B_TYPE = 18,
 258        MAX_SUBPARTS            = 19,
 259};
 260
 261/*
 262 * There are two order requirements for an IFWI image:
 263 * 1. Order in which the sub-partitions lie within the BPDT entries.
 264 * 2. Order in which the sub-partitions lie within the image.
 265 *
 266 * header_order defines #1 i.e. the order in which the sub-partitions should
 267 * appear in the BPDT entries. pack_order defines #2 i.e. the order in which
 268 * sub-partitions appear in the IFWI image. pack_order controls the offset and
 269 * thus sub-partitions would have increasing offsets as we loop over pack_order.
 270 */
 271const enum bpdt_entry_type bpdt_header_order[MAX_SUBPARTS] = {
 272        /* Order of the following entries is mandatory */
 273        CSE_IDLM_TYPE,
 274        IFP_OVERRIDE_TYPE,
 275        S_BPDT_TYPE,
 276        CSE_RBE_TYPE,
 277        UFS_PHY_TYPE,
 278        UFS_GPP_TYPE,
 279        /* Order of the following entries is recommended */
 280        UEP_TYPE,
 281        NVM_CONFIG_TYPE,
 282        UFS_RATE_B_TYPE,
 283        IBB_TYPE,
 284        SMIP_TYPE,
 285        PMC_TYPE,
 286        CSE_BUP_TYPE,
 287        UCODE_TYPE,
 288        DEBUG_TOKENS_TYPE,
 289        IUNIT_TYPE,
 290        CSE_MAIN_TYPE,
 291        ISH_TYPE,
 292        OBB_TYPE,
 293};
 294
 295const enum bpdt_entry_type bpdt_pack_order[MAX_SUBPARTS] = {
 296        /* Order of the following entries is mandatory */
 297        UFS_GPP_TYPE,
 298        UFS_PHY_TYPE,
 299        IFP_OVERRIDE_TYPE,
 300        UEP_TYPE,
 301        NVM_CONFIG_TYPE,
 302        UFS_RATE_B_TYPE,
 303        /* Order of the following entries is recommended */
 304        IBB_TYPE,
 305        SMIP_TYPE,
 306        CSE_RBE_TYPE,
 307        PMC_TYPE,
 308        CSE_BUP_TYPE,
 309        UCODE_TYPE,
 310        CSE_IDLM_TYPE,
 311        DEBUG_TOKENS_TYPE,
 312        S_BPDT_TYPE,
 313        IUNIT_TYPE,
 314        CSE_MAIN_TYPE,
 315        ISH_TYPE,
 316        OBB_TYPE,
 317};
 318
 319/* Utility functions */
 320enum ifwi_ret {
 321        COMMAND_ERR = -1,
 322        NO_ACTION_REQUIRED = 0,
 323        REPACK_REQUIRED = 1,
 324};
 325
 326struct dir_ops {
 327        enum ifwi_ret (*dir_add)(int type);
 328};
 329
 330static enum ifwi_ret ibbp_dir_add(int type);
 331
 332const struct subpart_info {
 333        const char *name;
 334        const char *readable_name;
 335        uint32_t attr;
 336        struct dir_ops dir_ops;
 337} subparts[MAX_SUBPARTS] = {
 338        /* OEM SMIP */
 339        [SMIP_TYPE] = {"SMIP", "SMIP", CONTAINS_DIR, {NULL} },
 340        /* CSE RBE */
 341        [CSE_RBE_TYPE] = {"RBEP", "CSE_RBE", CONTAINS_DIR |
 342                          MANDATORY_BPDT_ENTRY, {NULL} },
 343        /* CSE BUP */
 344        [CSE_BUP_TYPE] = {"FTPR", "CSE_BUP", CONTAINS_DIR |
 345                          MANDATORY_BPDT_ENTRY, {NULL} },
 346        /* uCode */
 347        [UCODE_TYPE] = {"UCOD", "Microcode", CONTAINS_DIR, {NULL} },
 348        /* IBB */
 349        [IBB_TYPE] = {"IBBP", "Bootblock", CONTAINS_DIR, {ibbp_dir_add} },
 350        /* S-BPDT */
 351        [S_BPDT_TYPE] = {"S_BPDT", "S-BPDT", AUTO_GENERATED |
 352                         MANDATORY_BPDT_ENTRY, {NULL} },
 353        /* OBB */
 354        [OBB_TYPE] = {"OBBP", "OEM boot block", CONTAINS_DIR |
 355                      NON_CRITICAL_SUBPART, {NULL} },
 356        /* CSE Main */
 357        [CSE_MAIN_TYPE] = {"NFTP", "CSE_MAIN", CONTAINS_DIR |
 358                           NON_CRITICAL_SUBPART, {NULL} },
 359        /* ISH */
 360        [ISH_TYPE] = {"ISHP", "ISH", NON_CRITICAL_SUBPART, {NULL} },
 361        /* CSE IDLM */
 362        [CSE_IDLM_TYPE] = {"DLMP", "CSE_IDLM", CONTAINS_DIR |
 363                           MANDATORY_BPDT_ENTRY, {NULL} },
 364        /* IFP Override */
 365        [IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
 366                               LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
 367                               {NULL} },
 368        /* Debug Tokens */
 369        [DEBUG_TOKENS_TYPE] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL} },
 370        /* UFS Phy Configuration */
 371        [UFS_PHY_TYPE] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K |
 372                          MANDATORY_BPDT_ENTRY, {NULL} },
 373        /* UFS GPP LUN ID */
 374        [UFS_GPP_TYPE] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K |
 375                          MANDATORY_BPDT_ENTRY, {NULL} },
 376        /* PMC */
 377        [PMC_TYPE] = {"PMCP", "PMC firmware", CONTAINS_DIR, {NULL} },
 378        /* IUNIT */
 379        [IUNIT_TYPE] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART, {NULL} },
 380        /* NVM Config */
 381        [NVM_CONFIG_TYPE] = {"NVM_CONFIG", "NVM Config", 0, {NULL} },
 382        /* UEP */
 383        [UEP_TYPE] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
 384                      {NULL} },
 385        /* UFS Rate B Config */
 386        [UFS_RATE_B_TYPE] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL} },
 387};
 388
 389struct ifwi_image {
 390        /* Data read from input file */
 391        struct buffer input_buff;
 392
 393        /* BPDT header and entries */
 394        struct buffer bpdt;
 395        size_t input_ifwi_start_offset;
 396        size_t input_ifwi_end_offset;
 397
 398        /* Subpartition content */
 399        struct buffer subpart_buf[MAX_SUBPARTS];
 400} ifwi_image;
 401
 402/* Buffer and file I/O */
 403static off_t get_file_size(FILE *f)
 404{
 405        off_t fsize;
 406
 407        fseek(f, 0, SEEK_END);
 408        fsize = ftell(f);
 409        fseek(f, 0, SEEK_SET);
 410        return fsize;
 411}
 412
 413static inline void *buffer_get(const struct buffer *b)
 414{
 415        return b->data;
 416}
 417
 418static inline size_t buffer_size(const struct buffer *b)
 419{
 420        return b->size;
 421}
 422
 423static inline size_t buffer_offset(const struct buffer *b)
 424{
 425        return b->offset;
 426}
 427
 428/*
 429 * Shrink a buffer toward the beginning of its previous space.
 430 * Afterward, buffer_delete() remains the means of cleaning it up
 431 */
 432static inline void buffer_set_size(struct buffer *b, size_t size)
 433{
 434        b->size = size;
 435}
 436
 437/* Splice a buffer into another buffer. Note that it's up to the caller to
 438 * bounds check the offset and size. The resulting buffer is backed by the same
 439 * storage as the original, so although it is valid to buffer_delete() either
 440 * one of them, doing so releases both simultaneously
 441 */
 442static void buffer_splice(struct buffer *dest, const struct buffer *src,
 443                          size_t offset, size_t size)
 444{
 445        dest->name = src->name;
 446        dest->data = src->data + offset;
 447        dest->offset = src->offset + offset;
 448        dest->size = size;
 449}
 450
 451/*
 452 * Shrink a buffer toward the end of its previous space.
 453 * Afterward, buffer_delete() remains the means of cleaning it up
 454 */
 455static inline void buffer_seek(struct buffer *b, size_t size)
 456{
 457        b->offset += size;
 458        b->size -= size;
 459        b->data += size;
 460}
 461
 462/* Returns the start of the underlying buffer, with the offset undone */
 463static inline void *buffer_get_original_backing(const struct buffer *b)
 464{
 465        if (!b)
 466                return NULL;
 467        return buffer_get(b) - buffer_offset(b);
 468}
 469
 470int buffer_create(struct buffer *buffer, size_t size, const char *name)
 471{
 472        buffer->name = strdup(name);
 473        buffer->offset = 0;
 474        buffer->size = size;
 475        buffer->data = (char *)malloc(buffer->size);
 476        if (!buffer->data) {
 477                fprintf(stderr, "%s: Insufficient memory (0x%zx).\n", __func__,
 478                        size);
 479        }
 480
 481        return !buffer->data;
 482}
 483
 484int buffer_write_file(struct buffer *buffer, const char *filename)
 485{
 486        FILE *fp = fopen(filename, "wb");
 487
 488        if (!fp) {
 489                perror(filename);
 490                return -1;
 491        }
 492        assert(buffer && buffer->data);
 493        if (fwrite(buffer->data, 1, buffer->size, fp) != buffer->size) {
 494                fprintf(stderr, "incomplete write: %s\n", filename);
 495                fclose(fp);
 496                return -1;
 497        }
 498        fclose(fp);
 499        return 0;
 500}
 501
 502void buffer_delete(struct buffer *buffer)
 503{
 504        assert(buffer);
 505        if (buffer->name) {
 506                free(buffer->name);
 507                buffer->name = NULL;
 508        }
 509        if (buffer->data) {
 510                free(buffer_get_original_backing(buffer));
 511                buffer->data = NULL;
 512        }
 513        buffer->offset = 0;
 514        buffer->size = 0;
 515}
 516
 517int buffer_from_file(struct buffer *buffer, const char *filename)
 518{
 519        FILE *fp = fopen(filename, "rb");
 520
 521        if (!fp) {
 522                perror(filename);
 523                return -1;
 524        }
 525        buffer->offset = 0;
 526        off_t file_size = get_file_size(fp);
 527
 528        if (file_size < 0) {
 529                fprintf(stderr, "could not determine size of %s\n", filename);
 530                fclose(fp);
 531                return -1;
 532        }
 533        buffer->size = file_size;
 534        buffer->name = strdup(filename);
 535        buffer->data = (char *)malloc(buffer->size);
 536        assert(buffer->data);
 537        if (fread(buffer->data, 1, buffer->size, fp) != buffer->size) {
 538                fprintf(stderr, "incomplete read: %s\n", filename);
 539                fclose(fp);
 540                buffer_delete(buffer);
 541                return -1;
 542        }
 543        fclose(fp);
 544        return 0;
 545}
 546
 547static void alloc_buffer(struct buffer *b, size_t s, const char *n)
 548{
 549        if (buffer_create(b, s, n) == 0)
 550                return;
 551
 552        ERROR("Buffer allocation failure for %s (size = %zx).\n", n, s);
 553        exit(-1);
 554}
 555
 556/* Little-Endian functions */
 557static inline uint8_t read_ble8(const void *src)
 558{
 559        const uint8_t *s = src;
 560        return *s;
 561}
 562
 563static inline uint8_t read_at_ble8(const void *src, size_t offset)
 564{
 565        const uint8_t *s = src;
 566
 567        s += offset;
 568        return read_ble8(s);
 569}
 570
 571static inline void write_ble8(void *dest, uint8_t val)
 572{
 573        *(uint8_t *)dest = val;
 574}
 575
 576static inline void write_at_ble8(void *dest, uint8_t val, size_t offset)
 577{
 578        uint8_t *d = dest;
 579
 580        d += offset;
 581        write_ble8(d, val);
 582}
 583
 584static inline uint8_t read_at_le8(const void *src, size_t offset)
 585{
 586        return read_at_ble8(src, offset);
 587}
 588
 589static inline void write_le8(void *dest, uint8_t val)
 590{
 591        write_ble8(dest, val);
 592}
 593
 594static inline void write_at_le8(void *dest, uint8_t val, size_t offset)
 595{
 596        write_at_ble8(dest, val, offset);
 597}
 598
 599static inline uint16_t read_le16(const void *src)
 600{
 601        const uint8_t *s = src;
 602
 603        return (((uint16_t)s[1]) << 8) | (((uint16_t)s[0]) << 0);
 604}
 605
 606static inline uint16_t read_at_le16(const void *src, size_t offset)
 607{
 608        const uint8_t *s = src;
 609
 610        s += offset;
 611        return read_le16(s);
 612}
 613
 614static inline void write_le16(void *dest, uint16_t val)
 615{
 616        write_le8(dest, val >> 0);
 617        write_at_le8(dest, val >> 8, sizeof(uint8_t));
 618}
 619
 620static inline void write_at_le16(void *dest, uint16_t val, size_t offset)
 621{
 622        uint8_t *d = dest;
 623
 624        d += offset;
 625        write_le16(d, val);
 626}
 627
 628static inline uint32_t read_le32(const void *src)
 629{
 630        const uint8_t *s = src;
 631
 632        return (((uint32_t)s[3]) << 24) | (((uint32_t)s[2]) << 16) |
 633                (((uint32_t)s[1]) << 8) | (((uint32_t)s[0]) << 0);
 634}
 635
 636static inline uint32_t read_at_le32(const void *src, size_t offset)
 637{
 638        const uint8_t *s = src;
 639
 640        s += offset;
 641        return read_le32(s);
 642}
 643
 644static inline void write_le32(void *dest, uint32_t val)
 645{
 646        write_le16(dest, val >> 0);
 647        write_at_le16(dest, val >> 16, sizeof(uint16_t));
 648}
 649
 650static inline void write_at_le32(void *dest, uint32_t val, size_t offset)
 651{
 652        uint8_t *d = dest;
 653
 654        d += offset;
 655        write_le32(d, val);
 656}
 657
 658static inline uint64_t read_le64(const void *src)
 659{
 660        uint64_t val;
 661
 662        val = read_at_le32(src, sizeof(uint32_t));
 663        val <<= 32;
 664        val |= read_le32(src);
 665        return val;
 666}
 667
 668static inline uint64_t read_at_le64(const void *src, size_t offset)
 669{
 670        const uint8_t *s = src;
 671
 672        s += offset;
 673        return read_le64(s);
 674}
 675
 676static inline void write_le64(void *dest, uint64_t val)
 677{
 678        write_le32(dest, val >> 0);
 679        write_at_le32(dest, val >> 32, sizeof(uint32_t));
 680}
 681
 682static inline void write_at_le64(void *dest, uint64_t val, size_t offset)
 683{
 684        uint8_t *d = dest;
 685
 686        d += offset;
 687        write_le64(d, val);
 688}
 689
 690/*
 691 * Read header/entry members in little-endian format.
 692 * Returns the offset upto which the read was performed.
 693 */
 694static size_t read_member(void *src, size_t offset, size_t size_bytes,
 695                          void *dst)
 696{
 697        switch (size_bytes) {
 698        case 1:
 699                *(uint8_t *)dst = read_at_le8(src, offset);
 700                break;
 701        case 2:
 702                *(uint16_t *)dst = read_at_le16(src, offset);
 703                break;
 704        case 4:
 705                *(uint32_t *)dst = read_at_le32(src, offset);
 706                break;
 707        case 8:
 708                *(uint64_t *)dst = read_at_le64(src, offset);
 709                break;
 710        default:
 711                ERROR("Read size not supported %zd\n", size_bytes);
 712                exit(-1);
 713        }
 714
 715        return (offset + size_bytes);
 716}
 717
 718/*
 719 * Convert to little endian format.
 720 * Returns the offset upto which the fixup was performed.
 721 */
 722static size_t fix_member(void *data, size_t offset, size_t size_bytes)
 723{
 724        uint8_t *src = (uint8_t *)data + offset;
 725
 726        switch (size_bytes) {
 727        case 1:
 728                write_at_le8(data, *(uint8_t *)src, offset);
 729                break;
 730        case 2:
 731                write_at_le16(data, *(uint16_t *)src, offset);
 732                break;
 733        case 4:
 734                write_at_le32(data, *(uint32_t *)src, offset);
 735                break;
 736        case 8:
 737                write_at_le64(data, *(uint64_t *)src, offset);
 738                break;
 739        default:
 740                ERROR("Write size not supported %zd\n", size_bytes);
 741                exit(-1);
 742        }
 743        return (offset + size_bytes);
 744}
 745
 746static void print_subpart_dir(struct subpart_dir *s)
 747{
 748        if (verbose == 0)
 749                return;
 750
 751        size_t i;
 752
 753        printf("%-25s 0x%-23.8x\n", "Marker", s->h.marker);
 754        printf("%-25s %-25d\n", "Num entries", s->h.num_entries);
 755        printf("%-25s %-25d\n", "Header Version", s->h.header_version);
 756        printf("%-25s %-25d\n", "Entry Version", s->h.entry_version);
 757        printf("%-25s 0x%-23x\n", "Header Length", s->h.header_length);
 758        printf("%-25s 0x%-23x\n", "Checksum", s->h.checksum);
 759        printf("%-25s ", "Name");
 760        for (i = 0; i < sizeof(s->h.name); i++)
 761                printf("%c", s->h.name[i]);
 762
 763        printf("\n");
 764
 765        printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
 766               "Length", "Rsvd");
 767
 768        printf("=========================================================================================================================\n");
 769
 770        for (i = 0; i < s->h.num_entries; i++) {
 771                printf("%-25zd%-25.12s0x%-23x0x%-23x0x%-23x\n", i + 1,
 772                       s->e[i].name, s->e[i].offset, s->e[i].length,
 773                       s->e[i].rsvd);
 774        }
 775
 776        printf("=========================================================================================================================\n");
 777}
 778
 779static void bpdt_print_header(struct bpdt_header *h, const char *name)
 780{
 781        if (verbose == 0)
 782                return;
 783
 784        printf("%-25s %-25s\n", "Header", name);
 785        printf("%-25s 0x%-23.8x\n", "Signature", h->signature);
 786        printf("%-25s %-25d\n", "Descriptor count", h->descriptor_count);
 787        printf("%-25s %-25d\n", "BPDT Version", h->bpdt_version);
 788        printf("%-25s 0x%-23x\n", "XOR checksum", h->xor_redundant_block);
 789        printf("%-25s 0x%-23x\n", "IFWI Version", h->ifwi_version);
 790        printf("%-25s 0x%-23llx\n", "FIT Tool Version",
 791               (long long)h->fit_tool_version);
 792}
 793
 794static void bpdt_print_entries(struct bpdt_entry *e, size_t count,
 795                               const char *name)
 796{
 797        size_t i;
 798
 799        if (verbose == 0)
 800                return;
 801
 802        printf("%s entries\n", name);
 803
 804        printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
 805               "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
 806               "File Offset");
 807
 808        printf("=========================================================================================================================================================================================================\n");
 809
 810        for (i = 0; i < count; i++) {
 811                printf("%-25zd%-25s%-25s%-25d0x%-23.08x0x%-23x0x%-23x0x%-23zx\n",
 812                       i + 1, subparts[e[i].type].name,
 813                       subparts[e[i].type].readable_name, e[i].type, e[i].flags,
 814                       e[i].offset, e[i].size,
 815                       e[i].offset + ifwi_image.input_ifwi_start_offset);
 816        }
 817
 818        printf("=========================================================================================================================================================================================================\n");
 819}
 820
 821static void bpdt_validate_header(struct bpdt_header *h, const char *name)
 822{
 823        assert(h->signature == BPDT_SIGNATURE);
 824
 825        if (h->bpdt_version != 1) {
 826                ERROR("Invalid header : %s\n", name);
 827                exit(-1);
 828        }
 829
 830        DEBUG("Validated header : %s\n", name);
 831}
 832
 833static void bpdt_read_header(void *data, struct bpdt_header *h,
 834                             const char *name)
 835{
 836        size_t offset = 0;
 837
 838        offset = read_member(data, offset, sizeof(h->signature), &h->signature);
 839        offset = read_member(data, offset, sizeof(h->descriptor_count),
 840                             &h->descriptor_count);
 841        offset = read_member(data, offset, sizeof(h->bpdt_version),
 842                             &h->bpdt_version);
 843        offset = read_member(data, offset, sizeof(h->xor_redundant_block),
 844                             &h->xor_redundant_block);
 845        offset = read_member(data, offset, sizeof(h->ifwi_version),
 846                             &h->ifwi_version);
 847        read_member(data, offset, sizeof(h->fit_tool_version),
 848                    &h->fit_tool_version);
 849
 850        bpdt_validate_header(h, name);
 851        bpdt_print_header(h, name);
 852}
 853
 854static void bpdt_read_entries(void *data, struct bpdt *bpdt, const char *name)
 855{
 856        size_t i, offset = 0;
 857        struct bpdt_entry *e = &bpdt->e[0];
 858        size_t count = bpdt->h.descriptor_count;
 859
 860        for (i = 0; i < count; i++) {
 861                offset = read_member(data, offset, sizeof(e[i].type),
 862                                     &e[i].type);
 863                offset = read_member(data, offset, sizeof(e[i].flags),
 864                                     &e[i].flags);
 865                offset = read_member(data, offset, sizeof(e[i].offset),
 866                                     &e[i].offset);
 867                offset = read_member(data, offset, sizeof(e[i].size),
 868                                     &e[i].size);
 869        }
 870
 871        bpdt_print_entries(e, count, name);
 872}
 873
 874/*
 875 * Given type of sub-partition, identify BPDT entry for it.
 876 * Sub-Partition could lie either within BPDT or S-BPDT.
 877 */
 878static struct bpdt_entry *__find_entry_by_type(struct bpdt_entry *e,
 879                                               size_t count, int type)
 880{
 881        size_t i;
 882
 883        for (i = 0; i < count; i++) {
 884                if (e[i].type == type)
 885                        break;
 886        }
 887
 888        if (i == count)
 889                return NULL;
 890
 891        return &e[i];
 892}
 893
 894static struct bpdt_entry *find_entry_by_type(int type)
 895{
 896        struct bpdt *b = buffer_get(&ifwi_image.bpdt);
 897
 898        if (!b)
 899                return NULL;
 900
 901        struct bpdt_entry *curr = __find_entry_by_type(&b->e[0],
 902                                                       b->h.descriptor_count,
 903                                                       type);
 904
 905        if (curr)
 906                return curr;
 907
 908        b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
 909        if (!b)
 910                return NULL;
 911
 912        return __find_entry_by_type(&b->e[0], b->h.descriptor_count, type);
 913}
 914
 915/*
 916 * Find sub-partition type given its name. If the name does not exist, returns
 917 * -1.
 918 */
 919static int find_type_by_name(const char *name)
 920{
 921        int i;
 922
 923        for (i = 0; i < MAX_SUBPARTS; i++) {
 924                if ((strlen(subparts[i].name) == strlen(name)) &&
 925                    (!strcmp(subparts[i].name, name)))
 926                        break;
 927        }
 928
 929        if (i == MAX_SUBPARTS) {
 930                ERROR("Invalid sub-partition name %s.\n", name);
 931                return -1;
 932        }
 933
 934        return i;
 935}
 936
 937/*
 938 * Read the content of a sub-partition from input file and store it in
 939 * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
 940 *
 941 * Returns the maximum offset occupied by the sub-partitions.
 942 */
 943static size_t read_subpart_buf(void *data, size_t size, struct bpdt_entry *e,
 944                               size_t count)
 945{
 946        size_t i, type;
 947        struct buffer *buf;
 948        size_t max_offset = 0;
 949
 950        for (i = 0; i < count; i++) {
 951                type = e[i].type;
 952
 953                if (type >= MAX_SUBPARTS) {
 954                        ERROR("Invalid sub-partition type %zd.\n", type);
 955                        exit(-1);
 956                }
 957
 958                if (buffer_size(&ifwi_image.subpart_buf[type])) {
 959                        ERROR("Multiple sub-partitions of type %zd(%s).\n",
 960                              type, subparts[type].name);
 961                        exit(-1);
 962                }
 963
 964                if (e[i].size == 0) {
 965                        INFO("Dummy sub-partition %zd(%s). Skipping.\n", type,
 966                             subparts[type].name);
 967                        continue;
 968                }
 969
 970                assert((e[i].offset + e[i].size) <= size);
 971
 972                /*
 973                 * Sub-partitions in IFWI image are not in the same order as
 974                 * in BPDT entries. BPDT entires are in header_order whereas
 975                 * sub-partition offsets in the image are in pack_order.
 976                 */
 977                if ((e[i].offset + e[i].size) > max_offset)
 978                        max_offset = e[i].offset + e[i].size;
 979
 980                /*
 981                 * S-BPDT sub-partition contains information about all the
 982                 * non-critical sub-partitions. Thus, size of S-BPDT
 983                 * sub-partition equals size of S-BPDT plus size of all the
 984                 * non-critical sub-partitions. Thus, reading whole of S-BPDT
 985                 * here would be redundant as the non-critical partitions are
 986                 * read and allocated buffers separately. Also, S-BPDT requires
 987                 * special handling for reading header and entries.
 988                 */
 989                if (type == S_BPDT_TYPE)
 990                        continue;
 991
 992                buf = &ifwi_image.subpart_buf[type];
 993
 994                alloc_buffer(buf, e[i].size, subparts[type].name);
 995                memcpy(buffer_get(buf), (uint8_t *)data + e[i].offset,
 996                       e[i].size);
 997        }
 998
 999        assert(max_offset);
1000        return max_offset;
1001}
1002
1003/*
1004 * Allocate buffer for bpdt header, entries and all sub-partition content.
1005 * Returns offset in data where BPDT ends.
1006 */
1007static size_t alloc_bpdt_buffer(void *data, size_t size, size_t offset,
1008                                struct buffer *b, const char *name)
1009{
1010        struct bpdt_header bpdt_header;
1011
1012        assert((offset + BPDT_HEADER_SIZE) < size);
1013        bpdt_read_header((uint8_t *)data + offset, &bpdt_header, name);
1014
1015        /* Buffer to read BPDT header and entries */
1016        alloc_buffer(b, get_bpdt_size(&bpdt_header), name);
1017
1018        struct bpdt *bpdt = buffer_get(b);
1019
1020        memcpy(&bpdt->h, &bpdt_header, BPDT_HEADER_SIZE);
1021
1022        /*
1023         * If no entries are present, maximum offset occupied is (offset +
1024         * BPDT_HEADER_SIZE).
1025         */
1026        if (bpdt->h.descriptor_count == 0)
1027                return (offset + BPDT_HEADER_SIZE);
1028
1029        /* Read all entries */
1030        assert((offset + get_bpdt_size(&bpdt->h)) < size);
1031        bpdt_read_entries((uint8_t *)data + offset + BPDT_HEADER_SIZE, bpdt,
1032                          name);
1033
1034        /* Read all sub-partition content in subpart_buf */
1035        return read_subpart_buf(data, size, &bpdt->e[0],
1036                                bpdt->h.descriptor_count);
1037}
1038
1039static void parse_sbpdt(void *data, size_t size)
1040{
1041        struct bpdt_entry *s;
1042
1043        s  = find_entry_by_type(S_BPDT_TYPE);
1044        if (!s)
1045                return;
1046
1047        assert(size > s->offset);
1048
1049        alloc_bpdt_buffer(data, size, s->offset,
1050                          &ifwi_image.subpart_buf[S_BPDT_TYPE],
1051                          "S-BPDT");
1052}
1053
1054static uint8_t calc_checksum(struct subpart_dir *s)
1055{
1056        size_t size = subpart_dir_size(&s->h);
1057        uint8_t *data = (uint8_t *)s;
1058        uint8_t checksum = 0;
1059        size_t i;
1060        uint8_t old_checksum = s->h.checksum;
1061
1062        s->h.checksum = 0;
1063
1064        for (i = 0; i < size; i++)
1065                checksum += data[i];
1066
1067        s->h.checksum = old_checksum;
1068
1069        /* 2s complement */
1070        return -checksum;
1071}
1072
1073static void validate_subpart_dir(struct subpart_dir *s, const char *name,
1074                                 bool checksum_check)
1075{
1076        if (s->h.marker != SUBPART_DIR_MARKER ||
1077            s->h.header_version != SUBPART_DIR_HEADER_VERSION_SUPPORTED ||
1078            s->h.entry_version != SUBPART_DIR_ENTRY_VERSION_SUPPORTED ||
1079            s->h.header_length != SUBPART_DIR_HEADER_SIZE) {
1080                ERROR("Invalid subpart_dir for %s.\n", name);
1081                exit(-1);
1082        }
1083
1084        if (!checksum_check)
1085                return;
1086
1087        uint8_t checksum = calc_checksum(s);
1088
1089        if (checksum != s->h.checksum)
1090                ERROR("Invalid checksum for %s (Expected=0x%x, Actual=0x%x).\n",
1091                      name, checksum, s->h.checksum);
1092}
1093
1094static void validate_subpart_dir_without_checksum(struct subpart_dir *s,
1095                                                  const char *name)
1096{
1097        validate_subpart_dir(s, name, 0);
1098}
1099
1100static void validate_subpart_dir_with_checksum(struct subpart_dir *s,
1101                                               const char *name)
1102{
1103        validate_subpart_dir(s, name, 1);
1104}
1105
1106static void parse_subpart_dir(struct buffer *subpart_dir_buf,
1107                              struct buffer *input_buf, const char *name)
1108{
1109        struct subpart_dir_header hdr;
1110        size_t offset = 0;
1111        uint8_t *data = buffer_get(input_buf);
1112        size_t size = buffer_size(input_buf);
1113
1114        /* Read Subpart_Dir header */
1115        assert(size >= SUBPART_DIR_HEADER_SIZE);
1116        offset = read_member(data, offset, sizeof(hdr.marker), &hdr.marker);
1117        offset = read_member(data, offset, sizeof(hdr.num_entries),
1118                             &hdr.num_entries);
1119        offset = read_member(data, offset, sizeof(hdr.header_version),
1120                             &hdr.header_version);
1121        offset = read_member(data, offset, sizeof(hdr.entry_version),
1122                             &hdr.entry_version);
1123        offset = read_member(data, offset, sizeof(hdr.header_length),
1124                             &hdr.header_length);
1125        offset = read_member(data, offset, sizeof(hdr.checksum), &hdr.checksum);
1126        memcpy(hdr.name, data + offset, sizeof(hdr.name));
1127        offset += sizeof(hdr.name);
1128
1129        validate_subpart_dir_without_checksum((struct subpart_dir *)&hdr, name);
1130
1131        assert(size > subpart_dir_size(&hdr));
1132        alloc_buffer(subpart_dir_buf, subpart_dir_size(&hdr), "Subpart Dir");
1133        memcpy(buffer_get(subpart_dir_buf), &hdr, SUBPART_DIR_HEADER_SIZE);
1134
1135        /* Read Subpart Dir entries */
1136        struct subpart_dir *subpart_dir = buffer_get(subpart_dir_buf);
1137        struct subpart_dir_entry *e = &subpart_dir->e[0];
1138        uint32_t i;
1139
1140        for (i = 0; i < hdr.num_entries; i++) {
1141                memcpy(e[i].name, data + offset, sizeof(e[i].name));
1142                offset += sizeof(e[i].name);
1143                offset = read_member(data, offset, sizeof(e[i].offset),
1144                                     &e[i].offset);
1145                offset = read_member(data, offset, sizeof(e[i].length),
1146                                     &e[i].length);
1147                offset = read_member(data, offset, sizeof(e[i].rsvd),
1148                                     &e[i].rsvd);
1149        }
1150
1151        validate_subpart_dir_with_checksum(subpart_dir, name);
1152
1153        print_subpart_dir(subpart_dir);
1154}
1155
1156/* Parse input image file to identify different sub-partitions */
1157static int ifwi_parse(void)
1158{
1159        struct buffer *buff = &ifwi_image.input_buff;
1160        const char *image_name = param.image_name;
1161
1162        DEBUG("Parsing IFWI image...\n");
1163
1164        /* Read input file */
1165        if (buffer_from_file(buff, image_name)) {
1166                ERROR("Failed to read input file %s.\n", image_name);
1167                return -1;
1168        }
1169
1170        INFO("Buffer %p size 0x%zx\n", buff->data, buff->size);
1171
1172        /* Look for BPDT signature at 4K intervals */
1173        size_t offset = 0;
1174        void *data = buffer_get(buff);
1175
1176        while (offset < buffer_size(buff)) {
1177                if (read_at_le32(data, offset) == BPDT_SIGNATURE)
1178                        break;
1179                offset += 4 * KiB;
1180        }
1181
1182        if (offset >= buffer_size(buff)) {
1183                ERROR("Image does not contain BPDT!!\n");
1184                return -1;
1185        }
1186
1187        ifwi_image.input_ifwi_start_offset = offset;
1188        INFO("BPDT starts at offset 0x%zx.\n", offset);
1189
1190        data = (uint8_t *)data + offset;
1191        size_t ifwi_size = buffer_size(buff) - offset;
1192
1193        /* Read BPDT and sub-partitions */
1194        uintptr_t end_offset;
1195
1196        end_offset = ifwi_image.input_ifwi_start_offset +
1197                alloc_bpdt_buffer(data, ifwi_size, 0, &ifwi_image.bpdt, "BPDT");
1198
1199        /* Parse S-BPDT, if any */
1200        parse_sbpdt(data, ifwi_size);
1201
1202        /*
1203         * Store end offset of IFWI. Required for copying any trailing non-IFWI
1204         * part of the image.
1205         * ASSUMPTION: IFWI image always ends on a 4K boundary.
1206         */
1207        ifwi_image.input_ifwi_end_offset = ALIGN(end_offset, 4 * KiB);
1208        DEBUG("Parsing done.\n");
1209
1210        return 0;
1211}
1212
1213/*
1214 * This function is used by repack to count the number of BPDT and S-BPDT
1215 * entries that are present. It frees the current buffers used by the entries
1216 * and allocates fresh buffers that can be used for repacking. Returns BPDT
1217 * entries which are empty and need to be filled in.
1218 */
1219static void __bpdt_reset(struct buffer *b, size_t count, size_t size)
1220{
1221        size_t bpdt_size = BPDT_HEADER_SIZE + count * BPDT_ENTRY_SIZE;
1222
1223        assert(size >= bpdt_size);
1224
1225        /*
1226         * If buffer does not have the required size, allocate a fresh buffer.
1227         */
1228        if (buffer_size(b) != size) {
1229                struct buffer temp;
1230
1231                alloc_buffer(&temp, size, b->name);
1232                memcpy(buffer_get(&temp), buffer_get(b), buffer_size(b));
1233                buffer_delete(b);
1234                *b = temp;
1235        }
1236
1237        struct bpdt *bpdt = buffer_get(b);
1238        uint8_t *ptr = (uint8_t *)&bpdt->e[0];
1239        size_t entries_size = BPDT_ENTRY_SIZE * count;
1240
1241        /* Zero out BPDT entries */
1242        memset(ptr, 0, entries_size);
1243        /* Fill any pad-space with FF */
1244        memset(ptr + entries_size, 0xFF, size - bpdt_size);
1245
1246        bpdt->h.descriptor_count = count;
1247}
1248
1249static void bpdt_reset(void)
1250{
1251        size_t i;
1252        size_t bpdt_count = 0, sbpdt_count = 0, dummy_bpdt_count = 0;
1253
1254        /* Count number of BPDT and S-BPDT entries */
1255        for (i = 0; i < MAX_SUBPARTS; i++) {
1256                if (buffer_size(&ifwi_image.subpart_buf[i]) == 0) {
1257                        if (subparts[i].attr & MANDATORY_BPDT_ENTRY) {
1258                                bpdt_count++;
1259                                dummy_bpdt_count++;
1260                        }
1261                        continue;
1262                }
1263
1264                if (subparts[i].attr & NON_CRITICAL_SUBPART)
1265                        sbpdt_count++;
1266                else
1267                        bpdt_count++;
1268        }
1269
1270        DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count,
1271              dummy_bpdt_count, sbpdt_count);
1272
1273        /* Update BPDT if required */
1274        size_t bpdt_size = max(BPDT_MIN_SIZE,
1275                               BPDT_HEADER_SIZE + bpdt_count * BPDT_ENTRY_SIZE);
1276        __bpdt_reset(&ifwi_image.bpdt, bpdt_count, bpdt_size);
1277
1278        /* Update S-BPDT if required */
1279        bpdt_size = ALIGN(BPDT_HEADER_SIZE + sbpdt_count * BPDT_ENTRY_SIZE,
1280                          4 * KiB);
1281        __bpdt_reset(&ifwi_image.subpart_buf[S_BPDT_TYPE], sbpdt_count,
1282                     bpdt_size);
1283}
1284
1285/* Initialize BPDT entries in header order */
1286static void bpdt_entries_init_header_order(void)
1287{
1288        int i, type;
1289        size_t size;
1290
1291        struct bpdt *bpdt, *sbpdt, *curr;
1292        size_t bpdt_curr = 0, sbpdt_curr = 0, *count_ptr;
1293
1294        bpdt = buffer_get(&ifwi_image.bpdt);
1295        sbpdt = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1296
1297        for (i = 0; i < MAX_SUBPARTS; i++) {
1298                type = bpdt_header_order[i];
1299                size = buffer_size(&ifwi_image.subpart_buf[type]);
1300
1301                if (size == 0 && !(subparts[type].attr & MANDATORY_BPDT_ENTRY))
1302                        continue;
1303
1304                if (subparts[type].attr & NON_CRITICAL_SUBPART) {
1305                        curr = sbpdt;
1306                        count_ptr = &sbpdt_curr;
1307                } else {
1308                        curr = bpdt;
1309                        count_ptr = &bpdt_curr;
1310                }
1311
1312                assert(*count_ptr < curr->h.descriptor_count);
1313                curr->e[*count_ptr].type = type;
1314                curr->e[*count_ptr].flags = 0;
1315                curr->e[*count_ptr].offset = 0;
1316                curr->e[*count_ptr].size = size;
1317
1318                (*count_ptr)++;
1319        }
1320}
1321
1322static void pad_buffer(struct buffer *b, size_t size)
1323{
1324        size_t buff_size = buffer_size(b);
1325
1326        assert(buff_size <= size);
1327
1328        if (buff_size == size)
1329                return;
1330
1331        struct buffer temp;
1332
1333        alloc_buffer(&temp, size, b->name);
1334        uint8_t *data = buffer_get(&temp);
1335
1336        memcpy(data, buffer_get(b), buff_size);
1337        memset(data + buff_size, 0xFF, size - buff_size);
1338
1339        *b = temp;
1340}
1341
1342/* Initialize offsets of entries using pack order */
1343static void bpdt_entries_init_pack_order(void)
1344{
1345        int i, type;
1346        struct bpdt_entry *curr;
1347        size_t curr_offset, curr_end;
1348
1349        curr_offset = max(BPDT_MIN_SIZE, buffer_size(&ifwi_image.bpdt));
1350
1351        /*
1352         * There are two types of sub-partitions that need to be handled here:
1353         *   1. Sub-partitions that lie within the same 4K as BPDT
1354         *   2. Sub-partitions that lie outside the 4K of BPDT
1355         *
1356         * For sub-partitions of type # 1, there is no requirement on the start
1357         * or end of the sub-partition. They need to be packed in without any
1358         * holes left in between. If there is any empty space left after the end
1359         * of the last sub-partition in 4K of BPDT, then that space needs to be
1360         * padded with FF bytes, but the size of the last sub-partition remains
1361         * unchanged.
1362         *
1363         * For sub-partitions of type # 2, both the start and end should be a
1364         * multiple of 4K. If not, then it needs to be padded with FF bytes and
1365         * size adjusted such that the sub-partition ends on 4K boundary.
1366         */
1367
1368        /* #1 Sub-partitions that lie within same 4K as BPDT */
1369        struct buffer *last_bpdt_buff = &ifwi_image.bpdt;
1370
1371        for (i = 0; i < MAX_SUBPARTS; i++) {
1372                type = bpdt_pack_order[i];
1373                curr = find_entry_by_type(type);
1374
1375                if (!curr || curr->size == 0)
1376                        continue;
1377
1378                if (!(subparts[type].attr & LIES_WITHIN_BPDT_4K))
1379                        continue;
1380
1381                curr->offset = curr_offset;
1382                curr_offset = curr->offset + curr->size;
1383                last_bpdt_buff = &ifwi_image.subpart_buf[type];
1384                DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
1385                      type, curr_offset, curr->offset, curr->size,
1386                      buffer_size(&ifwi_image.subpart_buf[type]));
1387        }
1388
1389        /* Pad ff bytes if there is any empty space left in BPDT 4K */
1390        curr_end = ALIGN(curr_offset, 4 * KiB);
1391        pad_buffer(last_bpdt_buff,
1392                   buffer_size(last_bpdt_buff) + (curr_end - curr_offset));
1393        curr_offset = curr_end;
1394
1395        /* #2 Sub-partitions that lie outside of BPDT 4K */
1396        for (i = 0; i < MAX_SUBPARTS; i++) {
1397                type = bpdt_pack_order[i];
1398                curr = find_entry_by_type(type);
1399
1400                if (!curr || curr->size == 0)
1401                        continue;
1402
1403                if (subparts[type].attr & LIES_WITHIN_BPDT_4K)
1404                        continue;
1405
1406                assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1407                curr->offset = curr_offset;
1408                curr_end = ALIGN(curr->offset + curr->size, 4 * KiB);
1409                curr->size = curr_end - curr->offset;
1410
1411                pad_buffer(&ifwi_image.subpart_buf[type], curr->size);
1412
1413                curr_offset = curr_end;
1414                DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
1415                      type, curr_offset, curr->offset, curr->size,
1416                      buffer_size(&ifwi_image.subpart_buf[type]));
1417        }
1418
1419        /*
1420         * Update size of S-BPDT to include size of all non-critical
1421         * sub-partitions.
1422         *
1423         * Assumption: S-BPDT always lies at the end of IFWI image.
1424         */
1425        curr = find_entry_by_type(S_BPDT_TYPE);
1426        assert(curr);
1427
1428        assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1429        curr->size = curr_offset - curr->offset;
1430}
1431
1432/* Convert all members of BPDT to little-endian format */
1433static void bpdt_fixup_write_buffer(struct buffer *buf)
1434{
1435        struct bpdt *s = buffer_get(buf);
1436
1437        struct bpdt_header *h = &s->h;
1438        struct bpdt_entry *e = &s->e[0];
1439
1440        size_t count = h->descriptor_count;
1441
1442        size_t offset = 0;
1443
1444        offset = fix_member(&h->signature, offset, sizeof(h->signature));
1445        offset = fix_member(&h->descriptor_count, offset,
1446                            sizeof(h->descriptor_count));
1447        offset = fix_member(&h->bpdt_version, offset, sizeof(h->bpdt_version));
1448        offset = fix_member(&h->xor_redundant_block, offset,
1449                            sizeof(h->xor_redundant_block));
1450        offset = fix_member(&h->ifwi_version, offset, sizeof(h->ifwi_version));
1451        offset = fix_member(&h->fit_tool_version, offset,
1452                            sizeof(h->fit_tool_version));
1453
1454        uint32_t i;
1455
1456        for (i = 0; i < count; i++) {
1457                offset = fix_member(&e[i].type, offset, sizeof(e[i].type));
1458                offset = fix_member(&e[i].flags, offset, sizeof(e[i].flags));
1459                offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
1460                offset = fix_member(&e[i].size, offset, sizeof(e[i].size));
1461        }
1462}
1463
1464/* Write BPDT to output buffer after fixup */
1465static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src)
1466{
1467        bpdt_fixup_write_buffer(src);
1468        memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src));
1469}
1470
1471/*
1472 * Follows these steps to re-create image:
1473 * 1. Write any non-IFWI prefix.
1474 * 2. Write out BPDT header and entries.
1475 * 3. Write sub-partition buffers to respective offsets.
1476 * 4. Write any non-IFWI suffix.
1477 *
1478 * While performing the above steps, make sure that any empty holes are filled
1479 * with FF.
1480 */
1481static void ifwi_write(const char *image_name)
1482{
1483        struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE);
1484
1485        assert(s);
1486
1487        size_t ifwi_start, ifwi_end, file_end;
1488
1489        ifwi_start = ifwi_image.input_ifwi_start_offset;
1490        ifwi_end = ifwi_start + ALIGN(s->offset + s->size, 4 * KiB);
1491        file_end = ifwi_end + (buffer_size(&ifwi_image.input_buff) -
1492                               ifwi_image.input_ifwi_end_offset);
1493
1494        struct buffer b;
1495
1496        alloc_buffer(&b, file_end, "Final-IFWI");
1497
1498        uint8_t *input_data = buffer_get(&ifwi_image.input_buff);
1499        uint8_t *output_data = buffer_get(&b);
1500
1501        DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start,
1502              ifwi_end, file_end);
1503
1504        /* Copy non-IFWI prefix, if any */
1505        memcpy(output_data, input_data, ifwi_start);
1506
1507        DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start);
1508
1509        struct buffer ifwi;
1510
1511        buffer_splice(&ifwi, &b, ifwi_start, ifwi_end - ifwi_start);
1512        uint8_t *ifwi_data = buffer_get(&ifwi);
1513
1514        /* Copy sub-partitions using pack_order */
1515        struct bpdt_entry *curr;
1516        struct buffer *subpart_buf;
1517        int i, type;
1518
1519        for (i = 0; i < MAX_SUBPARTS; i++) {
1520                type = bpdt_pack_order[i];
1521
1522                if (type == S_BPDT_TYPE)
1523                        continue;
1524
1525                curr = find_entry_by_type(type);
1526
1527                if (!curr || !curr->size)
1528                        continue;
1529
1530                subpart_buf = &ifwi_image.subpart_buf[type];
1531
1532                DEBUG("curr->offset=0x%x, curr->size=0x%x, type=%d, write_size=0x%zx\n",
1533                      curr->offset, curr->size, type, buffer_size(subpart_buf));
1534
1535                assert((curr->offset + buffer_size(subpart_buf)) <=
1536                       buffer_size(&ifwi));
1537
1538                memcpy(ifwi_data + curr->offset, buffer_get(subpart_buf),
1539                       buffer_size(subpart_buf));
1540        }
1541
1542        /* Copy non-IFWI suffix, if any */
1543        if (ifwi_end != file_end) {
1544                memcpy(output_data + ifwi_end,
1545                       input_data + ifwi_image.input_ifwi_end_offset,
1546                       file_end - ifwi_end);
1547                DEBUG("Copied non-IFWI suffix (offset=0x%zx,size=0x%zx).\n",
1548                      ifwi_end, file_end - ifwi_end);
1549        }
1550
1551        /*
1552         * Convert BPDT to little-endian format and write it to output buffer.
1553         * S-BPDT is written first and then BPDT.
1554         */
1555        bpdt_write(&ifwi, s->offset, &ifwi_image.subpart_buf[S_BPDT_TYPE]);
1556        bpdt_write(&ifwi, 0, &ifwi_image.bpdt);
1557
1558        if (buffer_write_file(&b, image_name)) {
1559                ERROR("File write error\n");
1560                exit(-1);
1561        }
1562
1563        buffer_delete(&b);
1564        printf("Image written successfully to %s.\n", image_name);
1565}
1566
1567/*
1568 * Calculate size and offset of each sub-partition again since it might have
1569 * changed because of add/delete operation. Also, re-create BPDT and S-BPDT
1570 * entries and write back the new IFWI image to file.
1571 */
1572static void ifwi_repack(void)
1573{
1574        bpdt_reset();
1575        bpdt_entries_init_header_order();
1576        bpdt_entries_init_pack_order();
1577
1578        struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1579
1580        bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1581
1582        b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1583        bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1584
1585        DEBUG("Repack done.. writing image.\n");
1586        ifwi_write(param.image_name);
1587}
1588
1589static void init_subpart_dir_header(struct subpart_dir_header *hdr,
1590                                    size_t count, const char *name)
1591{
1592        memset(hdr, 0, sizeof(*hdr));
1593
1594        hdr->marker = SUBPART_DIR_MARKER;
1595        hdr->num_entries = count;
1596        hdr->header_version = SUBPART_DIR_HEADER_VERSION_SUPPORTED;
1597        hdr->entry_version = SUBPART_DIR_ENTRY_VERSION_SUPPORTED;
1598        hdr->header_length = SUBPART_DIR_HEADER_SIZE;
1599        memcpy(hdr->name, name, sizeof(hdr->name));
1600}
1601
1602static size_t init_subpart_dir_entry(struct subpart_dir_entry *e,
1603                                     struct buffer *b, size_t offset)
1604{
1605        memset(e, 0, sizeof(*e));
1606
1607        assert(strlen(b->name) <= sizeof(e->name));
1608        strncpy((char *)e->name, (char *)b->name, sizeof(e->name));
1609        e->offset = offset;
1610        e->length = buffer_size(b);
1611
1612        return (offset + buffer_size(b));
1613}
1614
1615static void init_manifest_header(struct manifest_header *hdr, size_t size)
1616{
1617        memset(hdr, 0, sizeof(*hdr));
1618
1619        hdr->header_type = 0x4;
1620        assert((MANIFEST_HDR_SIZE % DWORD_SIZE) == 0);
1621        hdr->header_length = MANIFEST_HDR_SIZE / DWORD_SIZE;
1622        hdr->header_version = 0x10000;
1623        hdr->vendor = 0x8086;
1624
1625        struct tm *local_time;
1626        time_t curr_time;
1627        char buffer[11];
1628
1629        curr_time = time(NULL);
1630        local_time = localtime(&curr_time);
1631        strftime(buffer, sizeof(buffer), "0x%Y%m%d", local_time);
1632        hdr->date = strtoul(buffer, NULL, 16);
1633
1634        assert((size % DWORD_SIZE) == 0);
1635        hdr->size = size / DWORD_SIZE;
1636        hdr->id = MANIFEST_ID_MAGIC;
1637}
1638
1639static void init_signed_pkg_info_ext(struct signed_pkg_info_ext *ext,
1640                                     size_t count, const char *name)
1641{
1642        memset(ext, 0, sizeof(*ext));
1643
1644        ext->ext_type = SIGNED_PKG_INFO_EXT_TYPE;
1645        ext->ext_length = SIGNED_PKG_INFO_EXT_SIZE + count * MODULE_SIZE;
1646        memcpy(ext->name, name, sizeof(ext->name));
1647}
1648
1649static void subpart_dir_fixup_write_buffer(struct buffer *buf)
1650{
1651        struct subpart_dir *s = buffer_get(buf);
1652        struct subpart_dir_header *h = &s->h;
1653        struct subpart_dir_entry *e = &s->e[0];
1654
1655        size_t count = h->num_entries;
1656        size_t offset = 0;
1657
1658        offset = fix_member(&h->marker, offset, sizeof(h->marker));
1659        offset = fix_member(&h->num_entries, offset, sizeof(h->num_entries));
1660        offset = fix_member(&h->header_version, offset,
1661                            sizeof(h->header_version));
1662        offset = fix_member(&h->entry_version, offset,
1663                            sizeof(h->entry_version));
1664        offset = fix_member(&h->header_length, offset,
1665                            sizeof(h->header_length));
1666        offset = fix_member(&h->checksum, offset, sizeof(h->checksum));
1667        offset += sizeof(h->name);
1668
1669        uint32_t i;
1670
1671        for (i = 0; i < count; i++) {
1672                offset += sizeof(e[i].name);
1673                offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
1674                offset = fix_member(&e[i].length, offset, sizeof(e[i].length));
1675                offset = fix_member(&e[i].rsvd, offset, sizeof(e[i].rsvd));
1676        }
1677}
1678
1679static void create_subpart(struct buffer *dst, struct buffer *info[],
1680                           size_t count, const char *name)
1681{
1682        struct buffer subpart_dir_buff;
1683        size_t size = SUBPART_DIR_HEADER_SIZE + count * SUBPART_DIR_ENTRY_SIZE;
1684
1685        alloc_buffer(&subpart_dir_buff, size, "subpart-dir");
1686
1687        struct subpart_dir_header *h = buffer_get(&subpart_dir_buff);
1688        struct subpart_dir_entry *e = (struct subpart_dir_entry *)(h + 1);
1689
1690        init_subpart_dir_header(h, count, name);
1691
1692        size_t curr_offset = size;
1693        size_t i;
1694
1695        for (i = 0; i < count; i++) {
1696                curr_offset = init_subpart_dir_entry(&e[i], info[i],
1697                                                     curr_offset);
1698        }
1699
1700        alloc_buffer(dst, curr_offset, name);
1701        uint8_t *data = buffer_get(dst);
1702
1703        for (i = 0; i < count; i++) {
1704                memcpy(data + e[i].offset, buffer_get(info[i]),
1705                       buffer_size(info[i]));
1706        }
1707
1708        h->checksum = calc_checksum(buffer_get(&subpart_dir_buff));
1709
1710        struct subpart_dir *dir = buffer_get(&subpart_dir_buff);
1711
1712        print_subpart_dir(dir);
1713
1714        subpart_dir_fixup_write_buffer(&subpart_dir_buff);
1715        memcpy(data, dir, buffer_size(&subpart_dir_buff));
1716
1717        buffer_delete(&subpart_dir_buff);
1718}
1719
1720static enum ifwi_ret ibbp_dir_add(int type)
1721{
1722        struct buffer manifest;
1723        struct signed_pkg_info_ext *ext;
1724        struct buffer ibbl;
1725        struct buffer ibb;
1726
1727#define DUMMY_IBB_SIZE                  (4 * KiB)
1728
1729        assert(type == IBB_TYPE);
1730
1731        /*
1732         * Entry # 1 - IBBP.man
1733         * Contains manifest header and signed pkg info extension.
1734         */
1735        size_t size = MANIFEST_HDR_SIZE + SIGNED_PKG_INFO_EXT_SIZE;
1736
1737        alloc_buffer(&manifest, size, "IBBP.man");
1738
1739        struct manifest_header *man_hdr = buffer_get(&manifest);
1740
1741        init_manifest_header(man_hdr, size);
1742
1743        ext = (struct signed_pkg_info_ext *)(man_hdr + 1);
1744
1745        init_signed_pkg_info_ext(ext, 0, subparts[type].name);
1746
1747        /* Entry # 2 - IBBL */
1748        if (buffer_from_file(&ibbl, param.file_name))
1749                return COMMAND_ERR;
1750
1751        /* Entry # 3 - IBB */
1752        alloc_buffer(&ibb, DUMMY_IBB_SIZE, "IBB");
1753        memset(buffer_get(&ibb), 0xFF, DUMMY_IBB_SIZE);
1754
1755        /* Create subpartition */
1756        struct buffer *info[] = {
1757                &manifest, &ibbl, &ibb,
1758        };
1759        create_subpart(&ifwi_image.subpart_buf[type], &info[0],
1760                       ARRAY_SIZE(info), subparts[type].name);
1761
1762        return REPACK_REQUIRED;
1763}
1764
1765static enum ifwi_ret ifwi_raw_add(int type)
1766{
1767        if (buffer_from_file(&ifwi_image.subpart_buf[type], param.file_name))
1768                return COMMAND_ERR;
1769
1770        printf("Sub-partition %s(%d) added from file %s.\n", param.subpart_name,
1771               type, param.file_name);
1772        return REPACK_REQUIRED;
1773}
1774
1775static enum ifwi_ret ifwi_dir_add(int type)
1776{
1777        if (!(subparts[type].attr & CONTAINS_DIR) ||
1778            !subparts[type].dir_ops.dir_add) {
1779                ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1780                      subparts[type].name, type);
1781                return COMMAND_ERR;
1782        }
1783
1784        if (!param.dentry_name) {
1785                ERROR("%s: -e option required\n", __func__);
1786                return COMMAND_ERR;
1787        }
1788
1789        enum ifwi_ret ret = subparts[type].dir_ops.dir_add(type);
1790
1791        if (ret != COMMAND_ERR)
1792                printf("Sub-partition %s(%d) entry %s added from file %s.\n",
1793                       param.subpart_name, type, param.dentry_name,
1794                       param.file_name);
1795        else
1796                ERROR("Sub-partition dir operation failed.\n");
1797
1798        return ret;
1799}
1800
1801static enum ifwi_ret ifwi_add(void)
1802{
1803        if (!param.file_name) {
1804                ERROR("%s: -f option required\n", __func__);
1805                return COMMAND_ERR;
1806        }
1807
1808        if (!param.subpart_name) {
1809                ERROR("%s: -n option required\n", __func__);
1810                return COMMAND_ERR;
1811        }
1812
1813        int type = find_type_by_name(param.subpart_name);
1814
1815        if (type == -1)
1816                return COMMAND_ERR;
1817
1818        const struct subpart_info *curr_subpart = &subparts[type];
1819
1820        if (curr_subpart->attr & AUTO_GENERATED) {
1821                ERROR("Cannot add auto-generated sub-partitions.\n");
1822                return COMMAND_ERR;
1823        }
1824
1825        if (buffer_size(&ifwi_image.subpart_buf[type])) {
1826                ERROR("Image already contains sub-partition %s(%d).\n",
1827                      param.subpart_name, type);
1828                return COMMAND_ERR;
1829        }
1830
1831        if (param.dir_ops)
1832                return ifwi_dir_add(type);
1833
1834        return ifwi_raw_add(type);
1835}
1836
1837static enum ifwi_ret ifwi_delete(void)
1838{
1839        if (!param.subpart_name) {
1840                ERROR("%s: -n option required\n", __func__);
1841                return COMMAND_ERR;
1842        }
1843
1844        int type = find_type_by_name(param.subpart_name);
1845
1846        if (type == -1)
1847                return COMMAND_ERR;
1848
1849        const struct subpart_info *curr_subpart = &subparts[type];
1850
1851        if (curr_subpart->attr & AUTO_GENERATED) {
1852                ERROR("Cannot delete auto-generated sub-partitions.\n");
1853                return COMMAND_ERR;
1854        }
1855
1856        if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1857                printf("Image does not contain sub-partition %s(%d).\n",
1858                       param.subpart_name, type);
1859                return NO_ACTION_REQUIRED;
1860        }
1861
1862        buffer_delete(&ifwi_image.subpart_buf[type]);
1863        printf("Sub-Partition %s(%d) deleted.\n", subparts[type].name, type);
1864        return REPACK_REQUIRED;
1865}
1866
1867static enum ifwi_ret ifwi_dir_extract(int type)
1868{
1869        if (!(subparts[type].attr & CONTAINS_DIR)) {
1870                ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1871                      subparts[type].name, type);
1872                return COMMAND_ERR;
1873        }
1874
1875        if (!param.dentry_name) {
1876                ERROR("%s: -e option required.\n", __func__);
1877                return COMMAND_ERR;
1878        }
1879
1880        struct buffer subpart_dir_buff;
1881
1882        parse_subpart_dir(&subpart_dir_buff, &ifwi_image.subpart_buf[type],
1883                          subparts[type].name);
1884
1885        uint32_t i;
1886        struct subpart_dir *s = buffer_get(&subpart_dir_buff);
1887
1888        for (i = 0; i < s->h.num_entries; i++) {
1889                if (!strncmp((char *)s->e[i].name, param.dentry_name,
1890                             sizeof(s->e[i].name)))
1891                        break;
1892        }
1893
1894        if (i == s->h.num_entries) {
1895                ERROR("Entry %s not found in subpartition for %s.\n",
1896                      param.dentry_name, param.subpart_name);
1897                exit(-1);
1898        }
1899
1900        struct buffer dst;
1901
1902        DEBUG("Splicing buffer at 0x%x size 0x%x\n", s->e[i].offset,
1903              s->e[i].length);
1904        buffer_splice(&dst, &ifwi_image.subpart_buf[type], s->e[i].offset,
1905                      s->e[i].length);
1906
1907        if (buffer_write_file(&dst, param.file_name))
1908                return COMMAND_ERR;
1909
1910        printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1911               param.subpart_name, type, param.dentry_name, param.file_name);
1912
1913        return NO_ACTION_REQUIRED;
1914}
1915
1916static enum ifwi_ret ifwi_raw_extract(int type)
1917{
1918        if (buffer_write_file(&ifwi_image.subpart_buf[type], param.file_name))
1919                return COMMAND_ERR;
1920
1921        printf("Sub-Partition %s(%d) stored in %s.\n", param.subpart_name, type,
1922               param.file_name);
1923
1924        return NO_ACTION_REQUIRED;
1925}
1926
1927static enum ifwi_ret ifwi_extract(void)
1928{
1929        if (!param.file_name) {
1930                ERROR("%s: -f option required\n", __func__);
1931                return COMMAND_ERR;
1932        }
1933
1934        if (!param.subpart_name) {
1935                ERROR("%s: -n option required\n", __func__);
1936                return COMMAND_ERR;
1937        }
1938
1939        int type = find_type_by_name(param.subpart_name);
1940
1941        if (type == -1)
1942                return COMMAND_ERR;
1943
1944        if (type == S_BPDT_TYPE) {
1945                INFO("Tool does not support raw extract for %s\n",
1946                     param.subpart_name);
1947                return NO_ACTION_REQUIRED;
1948        }
1949
1950        if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1951                ERROR("Image does not contain sub-partition %s(%d).\n",
1952                      param.subpart_name, type);
1953                return COMMAND_ERR;
1954        }
1955
1956        INFO("Extracting sub-partition %s(%d).\n", param.subpart_name, type);
1957        if (param.dir_ops)
1958                return ifwi_dir_extract(type);
1959
1960        return ifwi_raw_extract(type);
1961}
1962
1963static enum ifwi_ret ifwi_print(void)
1964{
1965        verbose += 2;
1966
1967        struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1968
1969        bpdt_print_header(&b->h, "BPDT");
1970        bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1971
1972        b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1973        bpdt_print_header(&b->h, "S-BPDT");
1974        bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1975
1976        if (param.dir_ops == 0) {
1977                verbose -= 2;
1978                return NO_ACTION_REQUIRED;
1979        }
1980
1981        int i;
1982        struct buffer subpart_dir_buf;
1983
1984        for (i = 0; i < MAX_SUBPARTS ; i++) {
1985                if (!(subparts[i].attr & CONTAINS_DIR) ||
1986                    (buffer_size(&ifwi_image.subpart_buf[i]) == 0))
1987                        continue;
1988
1989                parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[i],
1990                                  subparts[i].name);
1991                buffer_delete(&subpart_dir_buf);
1992        }
1993
1994        verbose -= 2;
1995
1996        return NO_ACTION_REQUIRED;
1997}
1998
1999static enum ifwi_ret ifwi_raw_replace(int type)
2000{
2001        buffer_delete(&ifwi_image.subpart_buf[type]);
2002        return ifwi_raw_add(type);
2003}
2004
2005static enum ifwi_ret ifwi_dir_replace(int type)
2006{
2007        if (!(subparts[type].attr & CONTAINS_DIR)) {
2008                ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
2009                      subparts[type].name, type);
2010                return COMMAND_ERR;
2011        }
2012
2013        if (!param.dentry_name) {
2014                ERROR("%s: -e option required.\n", __func__);
2015                return COMMAND_ERR;
2016        }
2017
2018        struct buffer subpart_dir_buf;
2019
2020        parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[type],
2021                          subparts[type].name);
2022
2023        uint32_t i;
2024        struct subpart_dir *s = buffer_get(&subpart_dir_buf);
2025
2026        for (i = 0; i < s->h.num_entries; i++) {
2027                if (!strcmp((char *)s->e[i].name, param.dentry_name))
2028                        break;
2029        }
2030
2031        if (i == s->h.num_entries) {
2032                ERROR("Entry %s not found in subpartition for %s.\n",
2033                      param.dentry_name, param.subpart_name);
2034                exit(-1);
2035        }
2036
2037        struct buffer b;
2038
2039        if (buffer_from_file(&b, param.file_name)) {
2040                ERROR("Failed to read %s\n", param.file_name);
2041                exit(-1);
2042        }
2043
2044        struct buffer dst;
2045        size_t dst_size = buffer_size(&ifwi_image.subpart_buf[type]) +
2046                                      buffer_size(&b) - s->e[i].length;
2047        size_t subpart_start = s->e[i].offset;
2048        size_t subpart_end = s->e[i].offset + s->e[i].length;
2049
2050        alloc_buffer(&dst, dst_size, ifwi_image.subpart_buf[type].name);
2051
2052        uint8_t *src_data = buffer_get(&ifwi_image.subpart_buf[type]);
2053        uint8_t *dst_data = buffer_get(&dst);
2054        size_t curr_offset = 0;
2055
2056        /* Copy data before the sub-partition entry */
2057        memcpy(dst_data + curr_offset, src_data, subpart_start);
2058        curr_offset += subpart_start;
2059
2060        /* Copy sub-partition entry */
2061        memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
2062        curr_offset += buffer_size(&b);
2063
2064        /* Copy remaining data */
2065        memcpy(dst_data + curr_offset, src_data + subpart_end,
2066               buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end);
2067
2068        /* Update sub-partition buffer */
2069        int offset = s->e[i].offset;
2070
2071        buffer_delete(&ifwi_image.subpart_buf[type]);
2072        ifwi_image.subpart_buf[type] = dst;
2073
2074        /* Update length of entry in the subpartition */
2075        s->e[i].length = buffer_size(&b);
2076        buffer_delete(&b);
2077
2078        /* Adjust offsets of affected entries in subpartition */
2079        offset = s->e[i].offset - offset;
2080        for (; i < s->h.num_entries; i++)
2081                s->e[i].offset += offset;
2082
2083        /* Re-calculate checksum */
2084        s->h.checksum = calc_checksum(s);
2085
2086        /* Convert members to litte-endian */
2087        subpart_dir_fixup_write_buffer(&subpart_dir_buf);
2088
2089        memcpy(dst_data, buffer_get(&subpart_dir_buf),
2090               buffer_size(&subpart_dir_buf));
2091
2092        buffer_delete(&subpart_dir_buf);
2093
2094        printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
2095               param.subpart_name, type, param.dentry_name, param.file_name);
2096
2097        return REPACK_REQUIRED;
2098}
2099
2100static enum ifwi_ret ifwi_replace(void)
2101{
2102        if (!param.file_name) {
2103                ERROR("%s: -f option required\n", __func__);
2104                return COMMAND_ERR;
2105        }
2106
2107        if (!param.subpart_name) {
2108                ERROR("%s: -n option required\n", __func__);
2109                return COMMAND_ERR;
2110        }
2111
2112        int type = find_type_by_name(param.subpart_name);
2113
2114        if (type == -1)
2115                return COMMAND_ERR;
2116
2117        const struct subpart_info *curr_subpart = &subparts[type];
2118
2119        if (curr_subpart->attr & AUTO_GENERATED) {
2120                ERROR("Cannot replace auto-generated sub-partitions.\n");
2121                return COMMAND_ERR;
2122        }
2123
2124        if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
2125                ERROR("Image does not contain sub-partition %s(%d).\n",
2126                      param.subpart_name, type);
2127                return COMMAND_ERR;
2128        }
2129
2130        if (param.dir_ops)
2131                return ifwi_dir_replace(type);
2132
2133        return ifwi_raw_replace(type);
2134}
2135
2136static enum ifwi_ret ifwi_create(void)
2137{
2138        /*
2139         * Create peels off any non-IFWI content present in the input buffer and
2140         * creates output file with only the IFWI present.
2141         */
2142
2143        if (!param.file_name) {
2144                ERROR("%s: -f option required\n", __func__);
2145                return COMMAND_ERR;
2146        }
2147
2148        /* Peel off any non-IFWI prefix */
2149        buffer_seek(&ifwi_image.input_buff,
2150                    ifwi_image.input_ifwi_start_offset);
2151        /* Peel off any non-IFWI suffix */
2152        buffer_set_size(&ifwi_image.input_buff,
2153                        ifwi_image.input_ifwi_end_offset -
2154                        ifwi_image.input_ifwi_start_offset);
2155
2156        /*
2157         * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
2158         */
2159        ifwi_image.input_ifwi_end_offset -= ifwi_image.input_ifwi_start_offset;
2160        ifwi_image.input_ifwi_start_offset = 0;
2161
2162        param.image_name = param.file_name;
2163
2164        return REPACK_REQUIRED;
2165}
2166
2167struct command {
2168        const char *name;
2169        const char *optstring;
2170        enum ifwi_ret (*function)(void);
2171};
2172
2173static const struct command commands[] = {
2174        {"add", "f:n:e:dvh?", ifwi_add},
2175        {"create", "f:vh?", ifwi_create},
2176        {"delete", "f:n:vh?", ifwi_delete},
2177        {"extract", "f:n:e:dvh?", ifwi_extract},
2178        {"print", "dh?", ifwi_print},
2179        {"replace", "f:n:e:dvh?", ifwi_replace},
2180};
2181
2182static struct option long_options[] = {
2183        {"subpart_dentry",  required_argument, 0, 'e'},
2184        {"file",            required_argument, 0, 'f'},
2185        {"help",            required_argument, 0, 'h'},
2186        {"name",            required_argument, 0, 'n'},
2187        {"dir_ops",         no_argument,       0, 'd'},
2188        {"verbose",         no_argument,       0, 'v'},
2189        {NULL,              0,                 0,  0 }
2190};
2191
2192static void usage(const char *name)
2193{
2194        printf("ifwitool: Utility for IFWI manipulation\n\n"
2195               "USAGE:\n"
2196               " %s [-h]\n"
2197               " %s FILE COMMAND [PARAMETERS]\n\n"
2198               "COMMANDs:\n"
2199               " add -f FILE -n NAME [-d -e ENTRY]\n"
2200               " create -f FILE\n"
2201               " delete -n NAME\n"
2202               " extract -f FILE -n NAME [-d -e ENTRY]\n"
2203               " print [-d]\n"
2204               " replace -f FILE -n NAME [-d -e ENTRY]\n"
2205               "OPTIONs:\n"
2206               " -f FILE : File to read/write/create/extract\n"
2207               " -d      : Perform directory operation\n"
2208               " -e ENTRY: Name of directory entry to operate on\n"
2209               " -v      : Verbose level\n"
2210               " -h      : Help message\n"
2211               " -n NAME : Name of sub-partition to operate on\n",
2212               name, name
2213               );
2214
2215        printf("\nNAME should be one of:\n");
2216        int i;
2217
2218        for (i = 0; i < MAX_SUBPARTS; i++)
2219                printf("%s(%s)\n", subparts[i].name, subparts[i].readable_name);
2220        printf("\n");
2221}
2222
2223int main(int argc, char **argv)
2224{
2225        if (argc < 3) {
2226                usage(argv[0]);
2227                return 1;
2228        }
2229
2230        param.image_name = argv[1];
2231        char *cmd = argv[2];
2232
2233        optind += 2;
2234
2235        uint32_t i;
2236
2237        for (i = 0; i < ARRAY_SIZE(commands); i++) {
2238                if (strcmp(cmd, commands[i].name) != 0)
2239                        continue;
2240
2241                int c;
2242
2243                while (1) {
2244                        int option_index;
2245
2246                        c = getopt_long(argc, argv, commands[i].optstring,
2247                                        long_options, &option_index);
2248
2249                        if (c == -1)
2250                                break;
2251
2252                        /* Filter out illegal long options */
2253                        if (!strchr(commands[i].optstring, c)) {
2254                                ERROR("%s: invalid option -- '%c'\n", argv[0],
2255                                      c);
2256                                c = '?';
2257                        }
2258
2259                        switch (c) {
2260                        case 'n':
2261                                param.subpart_name = optarg;
2262                                break;
2263                        case 'f':
2264                                param.file_name = optarg;
2265                                break;
2266                        case 'd':
2267                                param.dir_ops = 1;
2268                                break;
2269                        case 'e':
2270                                param.dentry_name = optarg;
2271                                break;
2272                        case 'v':
2273                                verbose++;
2274                                break;
2275                        case 'h':
2276                        case '?':
2277                                usage(argv[0]);
2278                                return 1;
2279                        default:
2280                                break;
2281                        }
2282                }
2283
2284                if (ifwi_parse()) {
2285                        ERROR("%s: ifwi parsing failed\n", argv[0]);
2286                        return 1;
2287                }
2288
2289                enum ifwi_ret ret = commands[i].function();
2290
2291                if (ret == COMMAND_ERR) {
2292                        ERROR("%s: failed execution\n", argv[0]);
2293                        return 1;
2294                }
2295
2296                if (ret == REPACK_REQUIRED)
2297                        ifwi_repack();
2298
2299                return 0;
2300        }
2301
2302        ERROR("%s: invalid command\n", argv[0]);
2303        return 1;
2304}
2305