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