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 void *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(s, offset, sizeof(h->signature)); 1445 offset = fix_member(s, offset, sizeof(h->descriptor_count)); 1446 offset = fix_member(s, offset, sizeof(h->bpdt_version)); 1447 offset = fix_member(s, offset, sizeof(h->xor_redundant_block)); 1448 offset = fix_member(s, offset, sizeof(h->ifwi_version)); 1449 offset = fix_member(s, offset, sizeof(h->fit_tool_version)); 1450 1451 uint32_t i; 1452 1453 for (i = 0; i < count; i++) { 1454 offset = fix_member(s, offset, sizeof(e[i].type)); 1455 offset = fix_member(s, offset, sizeof(e[i].flags)); 1456 offset = fix_member(s, offset, sizeof(e[i].offset)); 1457 offset = fix_member(s, offset, sizeof(e[i].size)); 1458 } 1459} 1460 1461/* Write BPDT to output buffer after fixup */ 1462static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src) 1463{ 1464 bpdt_fixup_write_buffer(src); 1465 memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src)); 1466} 1467 1468/* 1469 * Follows these steps to re-create image: 1470 * 1. Write any non-IFWI prefix. 1471 * 2. Write out BPDT header and entries. 1472 * 3. Write sub-partition buffers to respective offsets. 1473 * 4. Write any non-IFWI suffix. 1474 * 1475 * While performing the above steps, make sure that any empty holes are filled 1476 * with FF. 1477 */ 1478static void ifwi_write(const char *image_name) 1479{ 1480 struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE); 1481 1482 assert(s); 1483 1484 size_t ifwi_start, ifwi_end, file_end; 1485 1486 ifwi_start = ifwi_image.input_ifwi_start_offset; 1487 ifwi_end = ifwi_start + ALIGN(s->offset + s->size, 4 * KiB); 1488 file_end = ifwi_end + (buffer_size(&ifwi_image.input_buff) - 1489 ifwi_image.input_ifwi_end_offset); 1490 1491 struct buffer b; 1492 1493 alloc_buffer(&b, file_end, "Final-IFWI"); 1494 1495 uint8_t *input_data = buffer_get(&ifwi_image.input_buff); 1496 uint8_t *output_data = buffer_get(&b); 1497 1498 DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start, 1499 ifwi_end, file_end); 1500 1501 /* Copy non-IFWI prefix, if any */ 1502 memcpy(output_data, input_data, ifwi_start); 1503 1504 DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start); 1505 1506 struct buffer ifwi; 1507 1508 buffer_splice(&ifwi, &b, ifwi_start, ifwi_end - ifwi_start); 1509 uint8_t *ifwi_data = buffer_get(&ifwi); 1510 1511 /* Copy sub-partitions using pack_order */ 1512 struct bpdt_entry *curr; 1513 struct buffer *subpart_buf; 1514 int i, type; 1515 1516 for (i = 0; i < MAX_SUBPARTS; i++) { 1517 type = bpdt_pack_order[i]; 1518 1519 if (type == S_BPDT_TYPE) 1520 continue; 1521 1522 curr = find_entry_by_type(type); 1523 1524 if (!curr || !curr->size) 1525 continue; 1526 1527 subpart_buf = &ifwi_image.subpart_buf[type]; 1528 1529 DEBUG("curr->offset=0x%x, curr->size=0x%x, type=%d, write_size=0x%zx\n", 1530 curr->offset, curr->size, type, buffer_size(subpart_buf)); 1531 1532 assert((curr->offset + buffer_size(subpart_buf)) <= 1533 buffer_size(&ifwi)); 1534 1535 memcpy(ifwi_data + curr->offset, buffer_get(subpart_buf), 1536 buffer_size(subpart_buf)); 1537 } 1538 1539 /* Copy non-IFWI suffix, if any */ 1540 if (ifwi_end != file_end) { 1541 memcpy(output_data + ifwi_end, 1542 input_data + ifwi_image.input_ifwi_end_offset, 1543 file_end - ifwi_end); 1544 DEBUG("Copied non-IFWI suffix (offset=0x%zx,size=0x%zx).\n", 1545 ifwi_end, file_end - ifwi_end); 1546 } 1547 1548 /* 1549 * Convert BPDT to little-endian format and write it to output buffer. 1550 * S-BPDT is written first and then BPDT. 1551 */ 1552 bpdt_write(&ifwi, s->offset, &ifwi_image.subpart_buf[S_BPDT_TYPE]); 1553 bpdt_write(&ifwi, 0, &ifwi_image.bpdt); 1554 1555 if (buffer_write_file(&b, image_name)) { 1556 ERROR("File write error\n"); 1557 exit(-1); 1558 } 1559 1560 buffer_delete(&b); 1561 printf("Image written successfully to %s.\n", image_name); 1562} 1563 1564/* 1565 * Calculate size and offset of each sub-partition again since it might have 1566 * changed because of add/delete operation. Also, re-create BPDT and S-BPDT 1567 * entries and write back the new IFWI image to file. 1568 */ 1569static void ifwi_repack(void) 1570{ 1571 bpdt_reset(); 1572 bpdt_entries_init_header_order(); 1573 bpdt_entries_init_pack_order(); 1574 1575 struct bpdt *b = buffer_get(&ifwi_image.bpdt); 1576 1577 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT"); 1578 1579 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]); 1580 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT"); 1581 1582 DEBUG("Repack done.. writing image.\n"); 1583 ifwi_write(param.image_name); 1584} 1585 1586static void init_subpart_dir_header(struct subpart_dir_header *hdr, 1587 size_t count, const char *name) 1588{ 1589 memset(hdr, 0, sizeof(*hdr)); 1590 1591 hdr->marker = SUBPART_DIR_MARKER; 1592 hdr->num_entries = count; 1593 hdr->header_version = SUBPART_DIR_HEADER_VERSION_SUPPORTED; 1594 hdr->entry_version = SUBPART_DIR_ENTRY_VERSION_SUPPORTED; 1595 hdr->header_length = SUBPART_DIR_HEADER_SIZE; 1596 memcpy(hdr->name, name, sizeof(hdr->name)); 1597} 1598 1599static size_t init_subpart_dir_entry(struct subpart_dir_entry *e, 1600 struct buffer *b, size_t offset) 1601{ 1602 memset(e, 0, sizeof(*e)); 1603 1604 assert(strlen(b->name) <= sizeof(e->name)); 1605 strncpy((char *)e->name, (char *)b->name, sizeof(e->name)); 1606 e->offset = offset; 1607 e->length = buffer_size(b); 1608 1609 return (offset + buffer_size(b)); 1610} 1611 1612static void init_manifest_header(struct manifest_header *hdr, size_t size) 1613{ 1614 memset(hdr, 0, sizeof(*hdr)); 1615 1616 hdr->header_type = 0x4; 1617 assert((MANIFEST_HDR_SIZE % DWORD_SIZE) == 0); 1618 hdr->header_length = MANIFEST_HDR_SIZE / DWORD_SIZE; 1619 hdr->header_version = 0x10000; 1620 hdr->vendor = 0x8086; 1621 1622 struct tm *local_time; 1623 time_t curr_time; 1624 char buffer[11]; 1625 1626 curr_time = time(NULL); 1627 local_time = localtime(&curr_time); 1628 assert(local_time != NULL); 1629 1630 strftime(buffer, sizeof(buffer), "0x%Y%m%d", local_time); 1631 hdr->date = strtoul(buffer, NULL, 16); 1632 1633 assert((size % DWORD_SIZE) == 0); 1634 hdr->size = size / DWORD_SIZE; 1635 hdr->id = MANIFEST_ID_MAGIC; 1636} 1637 1638static void init_signed_pkg_info_ext(struct signed_pkg_info_ext *ext, 1639 size_t count, const char *name) 1640{ 1641 memset(ext, 0, sizeof(*ext)); 1642 1643 ext->ext_type = SIGNED_PKG_INFO_EXT_TYPE; 1644 ext->ext_length = SIGNED_PKG_INFO_EXT_SIZE + count * MODULE_SIZE; 1645 memcpy(ext->name, name, sizeof(ext->name)); 1646} 1647 1648static void subpart_dir_fixup_write_buffer(struct buffer *buf) 1649{ 1650 struct subpart_dir *s = buffer_get(buf); 1651 struct subpart_dir_header *h = &s->h; 1652 struct subpart_dir_entry *e = &s->e[0]; 1653 1654 size_t count = h->num_entries; 1655 size_t offset = 0; 1656 1657 offset = fix_member(s, offset, sizeof(h->marker)); 1658 offset = fix_member(s, offset, sizeof(h->num_entries)); 1659 offset = fix_member(s, offset, sizeof(h->header_version)); 1660 offset = fix_member(s, offset, sizeof(h->entry_version)); 1661 offset = fix_member(s, offset, sizeof(h->header_length)); 1662 offset = fix_member(s, offset, sizeof(h->checksum)); 1663 offset += sizeof(h->name); 1664 1665 uint32_t i; 1666 1667 for (i = 0; i < count; i++) { 1668 offset += sizeof(e[i].name); 1669 offset = fix_member(s, offset, sizeof(e[i].offset)); 1670 offset = fix_member(s, offset, sizeof(e[i].length)); 1671 offset = fix_member(s, offset, sizeof(e[i].rsvd)); 1672 } 1673} 1674 1675static void create_subpart(struct buffer *dst, struct buffer *info[], 1676 size_t count, const char *name) 1677{ 1678 struct buffer subpart_dir_buff; 1679 size_t size = SUBPART_DIR_HEADER_SIZE + count * SUBPART_DIR_ENTRY_SIZE; 1680 1681 alloc_buffer(&subpart_dir_buff, size, "subpart-dir"); 1682 1683 struct subpart_dir_header *h = buffer_get(&subpart_dir_buff); 1684 struct subpart_dir_entry *e = (struct subpart_dir_entry *)(h + 1); 1685 1686 init_subpart_dir_header(h, count, name); 1687 1688 size_t curr_offset = size; 1689 size_t i; 1690 1691 for (i = 0; i < count; i++) { 1692 curr_offset = init_subpart_dir_entry(&e[i], info[i], 1693 curr_offset); 1694 } 1695 1696 alloc_buffer(dst, curr_offset, name); 1697 uint8_t *data = buffer_get(dst); 1698 1699 for (i = 0; i < count; i++) { 1700 memcpy(data + e[i].offset, buffer_get(info[i]), 1701 buffer_size(info[i])); 1702 } 1703 1704 h->checksum = calc_checksum(buffer_get(&subpart_dir_buff)); 1705 1706 struct subpart_dir *dir = buffer_get(&subpart_dir_buff); 1707 1708 print_subpart_dir(dir); 1709 1710 subpart_dir_fixup_write_buffer(&subpart_dir_buff); 1711 memcpy(data, dir, buffer_size(&subpart_dir_buff)); 1712 1713 buffer_delete(&subpart_dir_buff); 1714} 1715 1716static enum ifwi_ret ibbp_dir_add(int type) 1717{ 1718 struct buffer manifest; 1719 struct signed_pkg_info_ext *ext; 1720 struct buffer ibbl; 1721 struct buffer ibb; 1722 1723#define DUMMY_IBB_SIZE (4 * KiB) 1724 1725 assert(type == IBB_TYPE); 1726 1727 /* 1728 * Entry # 1 - IBBP.man 1729 * Contains manifest header and signed pkg info extension. 1730 */ 1731 size_t size = MANIFEST_HDR_SIZE + SIGNED_PKG_INFO_EXT_SIZE; 1732 1733 alloc_buffer(&manifest, size, "IBBP.man"); 1734 1735 struct manifest_header *man_hdr = buffer_get(&manifest); 1736 1737 init_manifest_header(man_hdr, size); 1738 1739 ext = (struct signed_pkg_info_ext *)(man_hdr + 1); 1740 1741 init_signed_pkg_info_ext(ext, 0, subparts[type].name); 1742 1743 /* Entry # 2 - IBBL */ 1744 if (buffer_from_file(&ibbl, param.file_name)) 1745 return COMMAND_ERR; 1746 1747 /* Entry # 3 - IBB */ 1748 alloc_buffer(&ibb, DUMMY_IBB_SIZE, "IBB"); 1749 memset(buffer_get(&ibb), 0xFF, DUMMY_IBB_SIZE); 1750 1751 /* Create subpartition */ 1752 struct buffer *info[] = { 1753 &manifest, &ibbl, &ibb, 1754 }; 1755 create_subpart(&ifwi_image.subpart_buf[type], &info[0], 1756 ARRAY_SIZE(info), subparts[type].name); 1757 1758 return REPACK_REQUIRED; 1759} 1760 1761static enum ifwi_ret ifwi_raw_add(int type) 1762{ 1763 if (buffer_from_file(&ifwi_image.subpart_buf[type], param.file_name)) 1764 return COMMAND_ERR; 1765 1766 printf("Sub-partition %s(%d) added from file %s.\n", param.subpart_name, 1767 type, param.file_name); 1768 return REPACK_REQUIRED; 1769} 1770 1771static enum ifwi_ret ifwi_dir_add(int type) 1772{ 1773 if (!(subparts[type].attr & CONTAINS_DIR) || 1774 !subparts[type].dir_ops.dir_add) { 1775 ERROR("Sub-Partition %s(%d) does not support dir ops.\n", 1776 subparts[type].name, type); 1777 return COMMAND_ERR; 1778 } 1779 1780 if (!param.dentry_name) { 1781 ERROR("%s: -e option required\n", __func__); 1782 return COMMAND_ERR; 1783 } 1784 1785 enum ifwi_ret ret = subparts[type].dir_ops.dir_add(type); 1786 1787 if (ret != COMMAND_ERR) 1788 printf("Sub-partition %s(%d) entry %s added from file %s.\n", 1789 param.subpart_name, type, param.dentry_name, 1790 param.file_name); 1791 else 1792 ERROR("Sub-partition dir operation failed.\n"); 1793 1794 return ret; 1795} 1796 1797static enum ifwi_ret ifwi_add(void) 1798{ 1799 if (!param.file_name) { 1800 ERROR("%s: -f option required\n", __func__); 1801 return COMMAND_ERR; 1802 } 1803 1804 if (!param.subpart_name) { 1805 ERROR("%s: -n option required\n", __func__); 1806 return COMMAND_ERR; 1807 } 1808 1809 int type = find_type_by_name(param.subpart_name); 1810 1811 if (type == -1) 1812 return COMMAND_ERR; 1813 1814 const struct subpart_info *curr_subpart = &subparts[type]; 1815 1816 if (curr_subpart->attr & AUTO_GENERATED) { 1817 ERROR("Cannot add auto-generated sub-partitions.\n"); 1818 return COMMAND_ERR; 1819 } 1820 1821 if (buffer_size(&ifwi_image.subpart_buf[type])) { 1822 ERROR("Image already contains sub-partition %s(%d).\n", 1823 param.subpart_name, type); 1824 return COMMAND_ERR; 1825 } 1826 1827 if (param.dir_ops) 1828 return ifwi_dir_add(type); 1829 1830 return ifwi_raw_add(type); 1831} 1832 1833static enum ifwi_ret ifwi_delete(void) 1834{ 1835 if (!param.subpart_name) { 1836 ERROR("%s: -n option required\n", __func__); 1837 return COMMAND_ERR; 1838 } 1839 1840 int type = find_type_by_name(param.subpart_name); 1841 1842 if (type == -1) 1843 return COMMAND_ERR; 1844 1845 const struct subpart_info *curr_subpart = &subparts[type]; 1846 1847 if (curr_subpart->attr & AUTO_GENERATED) { 1848 ERROR("Cannot delete auto-generated sub-partitions.\n"); 1849 return COMMAND_ERR; 1850 } 1851 1852 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) { 1853 printf("Image does not contain sub-partition %s(%d).\n", 1854 param.subpart_name, type); 1855 return NO_ACTION_REQUIRED; 1856 } 1857 1858 buffer_delete(&ifwi_image.subpart_buf[type]); 1859 printf("Sub-Partition %s(%d) deleted.\n", subparts[type].name, type); 1860 return REPACK_REQUIRED; 1861} 1862 1863static enum ifwi_ret ifwi_dir_extract(int type) 1864{ 1865 if (!(subparts[type].attr & CONTAINS_DIR)) { 1866 ERROR("Sub-Partition %s(%d) does not support dir ops.\n", 1867 subparts[type].name, type); 1868 return COMMAND_ERR; 1869 } 1870 1871 if (!param.dentry_name) { 1872 ERROR("%s: -e option required.\n", __func__); 1873 return COMMAND_ERR; 1874 } 1875 1876 struct buffer subpart_dir_buff; 1877 1878 parse_subpart_dir(&subpart_dir_buff, &ifwi_image.subpart_buf[type], 1879 subparts[type].name); 1880 1881 uint32_t i; 1882 struct subpart_dir *s = buffer_get(&subpart_dir_buff); 1883 1884 for (i = 0; i < s->h.num_entries; i++) { 1885 if (!strncmp((char *)s->e[i].name, param.dentry_name, 1886 sizeof(s->e[i].name))) 1887 break; 1888 } 1889 1890 if (i == s->h.num_entries) { 1891 ERROR("Entry %s not found in subpartition for %s.\n", 1892 param.dentry_name, param.subpart_name); 1893 exit(-1); 1894 } 1895 1896 struct buffer dst; 1897 1898 DEBUG("Splicing buffer at 0x%x size 0x%x\n", s->e[i].offset, 1899 s->e[i].length); 1900 buffer_splice(&dst, &ifwi_image.subpart_buf[type], s->e[i].offset, 1901 s->e[i].length); 1902 1903 if (buffer_write_file(&dst, param.file_name)) 1904 return COMMAND_ERR; 1905 1906 printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n", 1907 param.subpart_name, type, param.dentry_name, param.file_name); 1908 1909 return NO_ACTION_REQUIRED; 1910} 1911 1912static enum ifwi_ret ifwi_raw_extract(int type) 1913{ 1914 if (buffer_write_file(&ifwi_image.subpart_buf[type], param.file_name)) 1915 return COMMAND_ERR; 1916 1917 printf("Sub-Partition %s(%d) stored in %s.\n", param.subpart_name, type, 1918 param.file_name); 1919 1920 return NO_ACTION_REQUIRED; 1921} 1922 1923static enum ifwi_ret ifwi_extract(void) 1924{ 1925 if (!param.file_name) { 1926 ERROR("%s: -f option required\n", __func__); 1927 return COMMAND_ERR; 1928 } 1929 1930 if (!param.subpart_name) { 1931 ERROR("%s: -n option required\n", __func__); 1932 return COMMAND_ERR; 1933 } 1934 1935 int type = find_type_by_name(param.subpart_name); 1936 1937 if (type == -1) 1938 return COMMAND_ERR; 1939 1940 if (type == S_BPDT_TYPE) { 1941 INFO("Tool does not support raw extract for %s\n", 1942 param.subpart_name); 1943 return NO_ACTION_REQUIRED; 1944 } 1945 1946 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) { 1947 ERROR("Image does not contain sub-partition %s(%d).\n", 1948 param.subpart_name, type); 1949 return COMMAND_ERR; 1950 } 1951 1952 INFO("Extracting sub-partition %s(%d).\n", param.subpart_name, type); 1953 if (param.dir_ops) 1954 return ifwi_dir_extract(type); 1955 1956 return ifwi_raw_extract(type); 1957} 1958 1959static enum ifwi_ret ifwi_print(void) 1960{ 1961 verbose += 2; 1962 1963 struct bpdt *b = buffer_get(&ifwi_image.bpdt); 1964 1965 bpdt_print_header(&b->h, "BPDT"); 1966 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT"); 1967 1968 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]); 1969 bpdt_print_header(&b->h, "S-BPDT"); 1970 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT"); 1971 1972 if (param.dir_ops == 0) { 1973 verbose -= 2; 1974 return NO_ACTION_REQUIRED; 1975 } 1976 1977 int i; 1978 struct buffer subpart_dir_buf; 1979 1980 for (i = 0; i < MAX_SUBPARTS ; i++) { 1981 if (!(subparts[i].attr & CONTAINS_DIR) || 1982 (buffer_size(&ifwi_image.subpart_buf[i]) == 0)) 1983 continue; 1984 1985 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[i], 1986 subparts[i].name); 1987 buffer_delete(&subpart_dir_buf); 1988 } 1989 1990 verbose -= 2; 1991 1992 return NO_ACTION_REQUIRED; 1993} 1994 1995static enum ifwi_ret ifwi_raw_replace(int type) 1996{ 1997 buffer_delete(&ifwi_image.subpart_buf[type]); 1998 return ifwi_raw_add(type); 1999} 2000 2001static enum ifwi_ret ifwi_dir_replace(int type) 2002{ 2003 if (!(subparts[type].attr & CONTAINS_DIR)) { 2004 ERROR("Sub-Partition %s(%d) does not support dir ops.\n", 2005 subparts[type].name, type); 2006 return COMMAND_ERR; 2007 } 2008 2009 if (!param.dentry_name) { 2010 ERROR("%s: -e option required.\n", __func__); 2011 return COMMAND_ERR; 2012 } 2013 2014 struct buffer subpart_dir_buf; 2015 2016 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[type], 2017 subparts[type].name); 2018 2019 uint32_t i; 2020 struct subpart_dir *s = buffer_get(&subpart_dir_buf); 2021 2022 for (i = 0; i < s->h.num_entries; i++) { 2023 if (!strcmp((char *)s->e[i].name, param.dentry_name)) 2024 break; 2025 } 2026 2027 if (i == s->h.num_entries) { 2028 ERROR("Entry %s not found in subpartition for %s.\n", 2029 param.dentry_name, param.subpart_name); 2030 exit(-1); 2031 } 2032 2033 struct buffer b; 2034 2035 if (buffer_from_file(&b, param.file_name)) { 2036 ERROR("Failed to read %s\n", param.file_name); 2037 exit(-1); 2038 } 2039 2040 struct buffer dst; 2041 size_t dst_size = buffer_size(&ifwi_image.subpart_buf[type]) + 2042 buffer_size(&b) - s->e[i].length; 2043 size_t subpart_start = s->e[i].offset; 2044 size_t subpart_end = s->e[i].offset + s->e[i].length; 2045 2046 alloc_buffer(&dst, dst_size, ifwi_image.subpart_buf[type].name); 2047 2048 uint8_t *src_data = buffer_get(&ifwi_image.subpart_buf[type]); 2049 uint8_t *dst_data = buffer_get(&dst); 2050 size_t curr_offset = 0; 2051 2052 /* Copy data before the sub-partition entry */ 2053 memcpy(dst_data + curr_offset, src_data, subpart_start); 2054 curr_offset += subpart_start; 2055 2056 /* Copy sub-partition entry */ 2057 memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b)); 2058 curr_offset += buffer_size(&b); 2059 2060 /* Copy remaining data */ 2061 memcpy(dst_data + curr_offset, src_data + subpart_end, 2062 buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end); 2063 2064 /* Update sub-partition buffer */ 2065 int offset = s->e[i].offset; 2066 2067 buffer_delete(&ifwi_image.subpart_buf[type]); 2068 ifwi_image.subpart_buf[type] = dst; 2069 2070 /* Update length of entry in the subpartition */ 2071 s->e[i].length = buffer_size(&b); 2072 buffer_delete(&b); 2073 2074 /* Adjust offsets of affected entries in subpartition */ 2075 offset = s->e[i].offset - offset; 2076 for (; i < s->h.num_entries; i++) 2077 s->e[i].offset += offset; 2078 2079 /* Re-calculate checksum */ 2080 s->h.checksum = calc_checksum(s); 2081 2082 /* Convert members to litte-endian */ 2083 subpart_dir_fixup_write_buffer(&subpart_dir_buf); 2084 2085 memcpy(dst_data, buffer_get(&subpart_dir_buf), 2086 buffer_size(&subpart_dir_buf)); 2087 2088 buffer_delete(&subpart_dir_buf); 2089 2090 printf("Sub-partition %s(%d) entry %s replaced from file %s.\n", 2091 param.subpart_name, type, param.dentry_name, param.file_name); 2092 2093 return REPACK_REQUIRED; 2094} 2095 2096static enum ifwi_ret ifwi_replace(void) 2097{ 2098 if (!param.file_name) { 2099 ERROR("%s: -f option required\n", __func__); 2100 return COMMAND_ERR; 2101 } 2102 2103 if (!param.subpart_name) { 2104 ERROR("%s: -n option required\n", __func__); 2105 return COMMAND_ERR; 2106 } 2107 2108 int type = find_type_by_name(param.subpart_name); 2109 2110 if (type == -1) 2111 return COMMAND_ERR; 2112 2113 const struct subpart_info *curr_subpart = &subparts[type]; 2114 2115 if (curr_subpart->attr & AUTO_GENERATED) { 2116 ERROR("Cannot replace auto-generated sub-partitions.\n"); 2117 return COMMAND_ERR; 2118 } 2119 2120 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) { 2121 ERROR("Image does not contain sub-partition %s(%d).\n", 2122 param.subpart_name, type); 2123 return COMMAND_ERR; 2124 } 2125 2126 if (param.dir_ops) 2127 return ifwi_dir_replace(type); 2128 2129 return ifwi_raw_replace(type); 2130} 2131 2132static enum ifwi_ret ifwi_create(void) 2133{ 2134 /* 2135 * Create peels off any non-IFWI content present in the input buffer and 2136 * creates output file with only the IFWI present. 2137 */ 2138 2139 if (!param.file_name) { 2140 ERROR("%s: -f option required\n", __func__); 2141 return COMMAND_ERR; 2142 } 2143 2144 /* Peel off any non-IFWI prefix */ 2145 buffer_seek(&ifwi_image.input_buff, 2146 ifwi_image.input_ifwi_start_offset); 2147 /* Peel off any non-IFWI suffix */ 2148 buffer_set_size(&ifwi_image.input_buff, 2149 ifwi_image.input_ifwi_end_offset - 2150 ifwi_image.input_ifwi_start_offset); 2151 2152 /* 2153 * Adjust start and end offset of IFWI now that non-IFWI prefix is gone. 2154 */ 2155 ifwi_image.input_ifwi_end_offset -= ifwi_image.input_ifwi_start_offset; 2156 ifwi_image.input_ifwi_start_offset = 0; 2157 2158 param.image_name = param.file_name; 2159 2160 return REPACK_REQUIRED; 2161} 2162 2163struct command { 2164 const char *name; 2165 const char *optstring; 2166 enum ifwi_ret (*function)(void); 2167}; 2168 2169static const struct command commands[] = { 2170 {"add", "f:n:e:dvh?", ifwi_add}, 2171 {"create", "f:vh?", ifwi_create}, 2172 {"delete", "f:n:vh?", ifwi_delete}, 2173 {"extract", "f:n:e:dvh?", ifwi_extract}, 2174 {"print", "dh?", ifwi_print}, 2175 {"replace", "f:n:e:dvh?", ifwi_replace}, 2176}; 2177 2178static struct option long_options[] = { 2179 {"subpart_dentry", required_argument, 0, 'e'}, 2180 {"file", required_argument, 0, 'f'}, 2181 {"help", required_argument, 0, 'h'}, 2182 {"name", required_argument, 0, 'n'}, 2183 {"dir_ops", no_argument, 0, 'd'}, 2184 {"verbose", no_argument, 0, 'v'}, 2185 {NULL, 0, 0, 0 } 2186}; 2187 2188static void usage(const char *name) 2189{ 2190 printf("ifwitool: Utility for IFWI manipulation\n\n" 2191 "USAGE:\n" 2192 " %s [-h]\n" 2193 " %s FILE COMMAND [PARAMETERS]\n\n" 2194 "COMMANDs:\n" 2195 " add -f FILE -n NAME [-d -e ENTRY]\n" 2196 " create -f FILE\n" 2197 " delete -n NAME\n" 2198 " extract -f FILE -n NAME [-d -e ENTRY]\n" 2199 " print [-d]\n" 2200 " replace -f FILE -n NAME [-d -e ENTRY]\n" 2201 "OPTIONs:\n" 2202 " -f FILE : File to read/write/create/extract\n" 2203 " -d : Perform directory operation\n" 2204 " -e ENTRY: Name of directory entry to operate on\n" 2205 " -v : Verbose level\n" 2206 " -h : Help message\n" 2207 " -n NAME : Name of sub-partition to operate on\n", 2208 name, name 2209 ); 2210 2211 printf("\nNAME should be one of:\n"); 2212 int i; 2213 2214 for (i = 0; i < MAX_SUBPARTS; i++) 2215 printf("%s(%s)\n", subparts[i].name, subparts[i].readable_name); 2216 printf("\n"); 2217} 2218 2219int main(int argc, char **argv) 2220{ 2221 if (argc < 3) { 2222 usage(argv[0]); 2223 return 1; 2224 } 2225 2226 param.image_name = argv[1]; 2227 char *cmd = argv[2]; 2228 2229 optind += 2; 2230 2231 uint32_t i; 2232 2233 for (i = 0; i < ARRAY_SIZE(commands); i++) { 2234 if (strcmp(cmd, commands[i].name) != 0) 2235 continue; 2236 2237 int c; 2238 2239 while (1) { 2240 int option_index; 2241 2242 c = getopt_long(argc, argv, commands[i].optstring, 2243 long_options, &option_index); 2244 2245 if (c == -1) 2246 break; 2247 2248 /* Filter out illegal long options */ 2249 if (!strchr(commands[i].optstring, c)) { 2250 ERROR("%s: invalid option -- '%c'\n", argv[0], 2251 c); 2252 c = '?'; 2253 } 2254 2255 switch (c) { 2256 case 'n': 2257 param.subpart_name = optarg; 2258 break; 2259 case 'f': 2260 param.file_name = optarg; 2261 break; 2262 case 'd': 2263 param.dir_ops = 1; 2264 break; 2265 case 'e': 2266 param.dentry_name = optarg; 2267 break; 2268 case 'v': 2269 verbose++; 2270 break; 2271 case 'h': 2272 case '?': 2273 usage(argv[0]); 2274 return 1; 2275 default: 2276 break; 2277 } 2278 } 2279 2280 if (ifwi_parse()) { 2281 ERROR("%s: ifwi parsing failed\n", argv[0]); 2282 return 1; 2283 } 2284 2285 enum ifwi_ret ret = commands[i].function(); 2286 2287 if (ret == COMMAND_ERR) { 2288 ERROR("%s: failed execution\n", argv[0]); 2289 return 1; 2290 } 2291 2292 if (ret == REPACK_REQUIRED) 2293 ifwi_repack(); 2294 2295 return 0; 2296 } 2297 2298 ERROR("%s: invalid command\n", argv[0]); 2299 return 1; 2300} 2301