2 * ifwitool, CLI utility for IFWI manipulation
4 * Copyright 2016 Google Inc.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; version 2 of the License.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
16 #include <commonlib/endian.h>
24 * BPDT is Boot Partition Descriptor Table. It is located at the start of a
25 * logical boot partition(LBP). It stores information about the critical
26 * sub-partitions present within the LBP.
28 * S-BPDT is Secondary Boot Partition Descriptor Table. It is located after the
29 * critical sub-partitions and contains information about the non-critical
30 * sub-partitions present within the LBP.
32 * Both tables are identified by BPDT_SIGNATURE stored at the start of the
35 #define BPDT_SIGNATURE (0x000055AA)
37 /* Parameters passed in by caller. */
39 const char *file_name
;
40 const char *subpart_name
;
41 const char *image_name
;
43 const char *dentry_name
;
48 * This is used to identify start of BPDT. It should always be
52 /* Count of BPDT entries present. */
53 uint16_t descriptor_count
;
54 /* Version - Currently supported = 1. */
55 uint16_t bpdt_version
;
56 /* Unused - Should be 0. */
57 uint32_t xor_redundant_block
;
58 /* Version of IFWI build. */
59 uint32_t ifwi_version
;
60 /* Version of FIT tool used to create IFWI. */
61 uint64_t fit_tool_version
;
62 } __attribute__((packed
));
63 #define BPDT_HEADER_SIZE (sizeof(struct bpdt_header))
66 /* Type of sub-partition. */
68 /* Attributes of sub-partition. */
70 /* Offset of sub-partition from beginning of LBP. */
72 /* Size in bytes of sub-partition. */
74 } __attribute__((packed
));
75 #define BPDT_ENTRY_SIZE (sizeof(struct bpdt_entry))
79 /* In practice, this could be an array of 0 to n entries. */
80 struct bpdt_entry e
[0];
81 } __attribute__((packed
));
83 static inline size_t get_bpdt_size(struct bpdt_header
*h
)
85 return (sizeof(*h
) + BPDT_ENTRY_SIZE
* h
->descriptor_count
);
88 /* Minimum size in bytes allocated to BPDT in IFWI. */
89 #define BPDT_MIN_SIZE (512)
91 /* Header to define directory header for sub-partition. */
92 struct subpart_dir_header
{
93 /* Should be SUBPART_DIR_MARKER. */
95 /* Number of directory entries in the sub-partition. */
97 /* Currenty supported - 1. */
98 uint8_t header_version
;
99 /* Currenty supported - 1. */
100 uint8_t entry_version
;
101 /* Length of directory header in bytes. */
102 uint8_t header_length
;
104 * 2s complement of 8-bit sum from first byte of header to last byte of
105 * last directory entry.
108 /* ASCII short name of sub-partition. */
110 } __attribute__((packed
));
111 #define SUBPART_DIR_HEADER_SIZE \
112 (sizeof(struct subpart_dir_header))
113 #define SUBPART_DIR_MARKER 0x44504324
114 #define SUBPART_DIR_HEADER_VERSION_SUPPORTED 1
115 #define SUBPART_DIR_ENTRY_VERSION_SUPPORTED 1
117 /* Structure for each directory entry for sub-partition. */
118 struct subpart_dir_entry
{
119 /* Name of directory entry - Not guaranteed to be NULL-terminated. */
121 /* Offset of entry from beginning of sub-partition. */
123 /* Length in bytes of sub-directory entry. */
127 } __attribute__((packed
));
128 #define SUBPART_DIR_ENTRY_SIZE \
129 (sizeof(struct subpart_dir_entry))
132 struct subpart_dir_header h
;
133 /* In practice, this could be an array of 0 to n entries. */
134 struct subpart_dir_entry e
[0];
135 } __attribute__((packed
));
137 static inline size_t subpart_dir_size(struct subpart_dir_header
*h
)
139 return (sizeof(*h
) + SUBPART_DIR_ENTRY_SIZE
* h
->num_entries
);
142 struct manifest_header
{
143 uint32_t header_type
;
144 uint32_t header_length
;
145 uint32_t header_version
;
156 uint32_t modulus_size
;
157 uint32_t exponent_size
;
158 uint8_t public_key
[256];
160 uint8_t signature
[256];
161 } __attribute__((packed
));
164 #define MANIFEST_HDR_SIZE (sizeof(struct manifest_header))
165 #define MANIFEST_ID_MAGIC (0x324e4d24)
172 uint32_t metadata_size
;
173 uint8_t metadata_hash
[32];
174 } __attribute__((packed
));
176 #define MODULE_SIZE (sizeof(struct module))
178 struct signed_pkg_info_ext
{
186 } __attribute__((packed
));
188 #define SIGNED_PKG_INFO_EXT_TYPE 0x15
189 #define SIGNED_PKG_INFO_EXT_SIZE \
190 (sizeof(struct signed_pkg_info_ext))
193 * Attributes for various IFWI sub-partitions.
194 * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
196 * NON_CRITICAL_SUBPART = Sub-Partition entry should be present in S-BPDT.
197 * CONTAINS_DIR = Sub-Partition contains directory.
198 * AUTO_GENERATED = Sub-Partition is generated by the tool.
199 * MANDATORY_BPDT_ENTRY = Even if sub-partition is deleted, BPDT should contain
200 * an entry for it with size 0 and offset 0.
202 enum subpart_attributes
{
203 LIES_WITHIN_BPDT_4K
= (1 << 0),
204 NON_CRITICAL_SUBPART
= (1 << 1),
205 CONTAINS_DIR
= (1 << 2),
206 AUTO_GENERATED
= (1 << 3),
207 MANDATORY_BPDT_ENTRY
= (1 << 4),
210 /* Type value for various IFWI sub-partitions. */
211 enum bpdt_entry_type
{
222 IFP_OVERRIDE_TYPE
= 10,
223 DEBUG_TOKENS_TYPE
= 11,
228 NVM_CONFIG_TYPE
= 16,
230 UFS_RATE_B_TYPE
= 18,
235 * There are two order requirements for an IFWI image:
236 * 1. Order in which the sub-partitions lie within the BPDT entries.
237 * 2. Order in which the sub-partitions lie within the image.
239 * header_order defines #1 i.e. the order in which the sub-partitions should
240 * appear in the BPDT entries. pack_order defines #2 i.e. the order in which
241 * sub-partitions appear in the IFWI image. pack_order controls the offset and
242 * thus sub-partitions would have increasing offsets as we loop over pack_order.
244 const enum bpdt_entry_type bpdt_header_order
[MAX_SUBPARTS
] = {
245 /* Order of the following entries is mandatory. */
252 /* Order of the following entries is recommended. */
268 const enum bpdt_entry_type bpdt_pack_order
[MAX_SUBPARTS
] = {
269 /* Order of the following entries is mandatory. */
276 /* Order of the following entries is recommended. */
292 /* Utility functions. */
295 NO_ACTION_REQUIRED
= 0,
300 enum ifwi_ret (*dir_add
)(int);
303 static enum ifwi_ret
ibbp_dir_add(int);
305 const struct subpart_info
{
307 const char *readable_name
;
309 struct dir_ops dir_ops
;
310 } subparts
[MAX_SUBPARTS
] = {
312 [SMIP_TYPE
] = {"SMIP", "SMIP", CONTAINS_DIR
, {NULL
} },
314 [CSE_RBE_TYPE
] = {"RBEP", "CSE_RBE", CONTAINS_DIR
|
315 MANDATORY_BPDT_ENTRY
, {NULL
} },
317 [CSE_BUP_TYPE
] = {"FTPR", "CSE_BUP", CONTAINS_DIR
|
318 MANDATORY_BPDT_ENTRY
, {NULL
} },
320 [UCODE_TYPE
] = {"UCOD", "Microcode", CONTAINS_DIR
, {NULL
} },
322 [IBB_TYPE
] = {"IBBP", "Bootblock", CONTAINS_DIR
, {ibbp_dir_add
} },
324 [S_BPDT_TYPE
] = {"S_BPDT", "S-BPDT", AUTO_GENERATED
|
325 MANDATORY_BPDT_ENTRY
, {NULL
} },
327 [OBB_TYPE
] = {"OBBP", "OEM boot block", CONTAINS_DIR
|
328 NON_CRITICAL_SUBPART
, {NULL
} },
330 [CSE_MAIN_TYPE
] = {"NFTP", "CSE_MAIN", CONTAINS_DIR
|
331 NON_CRITICAL_SUBPART
, {NULL
} },
333 [ISH_TYPE
] = {"ISHP", "ISH", NON_CRITICAL_SUBPART
, {NULL
} },
335 [CSE_IDLM_TYPE
] = {"DLMP", "CSE_IDLM", CONTAINS_DIR
|
336 MANDATORY_BPDT_ENTRY
, {NULL
} },
338 [IFP_OVERRIDE_TYPE
] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
339 LIES_WITHIN_BPDT_4K
| MANDATORY_BPDT_ENTRY
,
342 [DEBUG_TOKENS_TYPE
] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL
} },
343 /* UFS Phy Configuration */
344 [UFS_PHY_TYPE
] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K
|
345 MANDATORY_BPDT_ENTRY
, {NULL
} },
347 [UFS_GPP_TYPE
] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K
|
348 MANDATORY_BPDT_ENTRY
, {NULL
} },
350 [PMC_TYPE
] = {"PMCP", "PMC firmware", CONTAINS_DIR
, {NULL
} },
352 [IUNIT_TYPE
] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART
, {NULL
} },
354 [NVM_CONFIG_TYPE
] = {"NVM_CONFIG", "NVM Config", 0, {NULL
} },
356 [UEP_TYPE
] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K
| MANDATORY_BPDT_ENTRY
,
358 /* UFS Rate B Config */
359 [UFS_RATE_B_TYPE
] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL
} },
363 /* Data read from input file. */
364 struct buffer input_buff
;
366 /* BPDT header and entries. */
368 size_t input_ifwi_start_offset
;
369 size_t input_ifwi_end_offset
;
371 /* Subpartition content. */
372 struct buffer subpart_buf
[MAX_SUBPARTS
];
375 static void alloc_buffer(struct buffer
*b
, size_t s
, const char *n
)
377 if (buffer_create(b
, s
, n
) == 0)
380 ERROR("Buffer allocation failure for %s (size = %zx).\n", n
, s
);
385 * Read header/entry members in little-endian format.
386 * Returns the offset upto which the read was performed.
388 static size_t read_member(void *src
, size_t offset
, size_t size_bytes
,
391 switch (size_bytes
) {
393 *(uint8_t *)dst
= read_at_le8(src
, offset
);
396 *(uint16_t *)dst
= read_at_le16(src
, offset
);
399 *(uint32_t *)dst
= read_at_le32(src
, offset
);
402 *(uint64_t *)dst
= read_at_le64(src
, offset
);
405 ERROR("Read size not supported %zd\n", size_bytes
);
409 return (offset
+ size_bytes
);
413 * Convert to little endian format.
414 * Returns the offset upto which the fixup was performed.
416 static size_t fix_member(void *data
, size_t offset
, size_t size_bytes
)
418 uint8_t *src
= (uint8_t *)data
+ offset
;
420 switch (size_bytes
) {
422 write_at_le8(data
, *(uint8_t *)src
, offset
);
425 write_at_le16(data
, *(uint16_t *)src
, offset
);
428 write_at_le32(data
, *(uint32_t *)src
, offset
);
431 write_at_le64(data
, *(uint64_t *)src
, offset
);
434 ERROR("Write size not supported %zd\n", size_bytes
);
437 return (offset
+ size_bytes
);
441 static void print_subpart_dir(struct subpart_dir
*s
)
448 printf("%-25s 0x%-23.8x\n", "Marker", s
->h
.marker
);
449 printf("%-25s %-25d\n", "Num entries", s
->h
.num_entries
);
450 printf("%-25s %-25d\n", "Header Version", s
->h
.header_version
);
451 printf("%-25s %-25d\n", "Entry Version", s
->h
.entry_version
);
452 printf("%-25s 0x%-23x\n", "Header Length", s
->h
.header_length
);
453 printf("%-25s 0x%-23x\n", "Checksum", s
->h
.checksum
);
454 printf("%-25s ", "Name");
455 for (i
= 0; i
< sizeof(s
->h
.name
); i
++)
456 printf("%c", s
->h
.name
[i
]);
460 printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
463 printf("=============================================================="
464 "===========================================================\n");
466 for (i
= 0; i
< s
->h
.num_entries
; i
++) {
467 printf("%-25zd%-25.12s0x%-23x0x%-23x0x%-23x\n", i
+1,
468 s
->e
[i
].name
, s
->e
[i
].offset
, s
->e
[i
].length
,
472 printf("=============================================================="
473 "===========================================================\n");
476 static void bpdt_print_header(struct bpdt_header
*h
, const char *name
)
481 printf("%-25s %-25s\n", "Header", name
);
482 printf("%-25s 0x%-23.8x\n", "Signature", h
->signature
);
483 printf("%-25s %-25d\n", "Descriptor count", h
->descriptor_count
);
484 printf("%-25s %-25d\n", "BPDT Version", h
->bpdt_version
);
485 printf("%-25s 0x%-23x\n", "XOR checksum", h
->xor_redundant_block
);
486 printf("%-25s 0x%-23x\n", "IFWI Version", h
->ifwi_version
);
487 printf("%-25s 0x%-23llx\n", "FIT Tool Version",
488 (long long)h
->fit_tool_version
);
491 static void bpdt_print_entries(struct bpdt_entry
*e
, size_t count
,
497 printf("%s entries\n", name
);
499 printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
500 "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
503 printf("=============================================================="
504 "=============================================================="
505 "=============================================================="
506 "===============\n");
510 for (i
= 0; i
< count
; i
++) {
511 printf("%-25zd%-25s%-25s%-25d0x%-23.08x0x%-23x0x%-23x0x%-23zx"
512 "\n", i
+1, subparts
[e
[i
].type
].name
,
513 subparts
[e
[i
].type
].readable_name
, e
[i
].type
, e
[i
].flags
,
514 e
[i
].offset
, e
[i
].size
,
515 e
[i
].offset
+ ifwi_image
.input_ifwi_start_offset
);
518 printf("=============================================================="
519 "=============================================================="
520 "=============================================================="
521 "===============\n");
525 static void bpdt_validate_header(struct bpdt_header
*h
, const char *name
)
527 assert(h
->signature
== BPDT_SIGNATURE
);
529 if (h
->bpdt_version
!= 1) {
530 ERROR("Invalid header : %s\n", name
);
534 DEBUG("Validated header : %s\n", name
);
537 static void bpdt_read_header(void *data
, struct bpdt_header
*h
,
542 offset
= read_member(data
, offset
, sizeof(h
->signature
), &h
->signature
);
543 offset
= read_member(data
, offset
, sizeof(h
->descriptor_count
),
544 &h
->descriptor_count
);
545 offset
= read_member(data
, offset
, sizeof(h
->bpdt_version
),
547 offset
= read_member(data
, offset
, sizeof(h
->xor_redundant_block
),
548 &h
->xor_redundant_block
);
549 offset
= read_member(data
, offset
, sizeof(h
->ifwi_version
),
551 offset
= read_member(data
, offset
, sizeof(h
->fit_tool_version
),
552 &h
->fit_tool_version
);
554 bpdt_validate_header(h
, name
);
555 bpdt_print_header(h
, name
);
558 static void bpdt_read_entries(void *data
, struct bpdt
*bpdt
, const char *name
)
560 size_t i
, offset
= 0;
561 struct bpdt_entry
*e
= &bpdt
->e
[0];
562 size_t count
= bpdt
->h
.descriptor_count
;
564 for (i
= 0; i
< count
; i
++) {
565 offset
= read_member(data
, offset
, sizeof(e
[i
].type
),
567 offset
= read_member(data
, offset
, sizeof(e
[i
].flags
),
569 offset
= read_member(data
, offset
, sizeof(e
[i
].offset
),
571 offset
= read_member(data
, offset
, sizeof(e
[i
].size
),
575 bpdt_print_entries(e
, count
, name
);
579 * Given type of sub-partition, identify BPDT entry for it.
580 * Sub-Partition could lie either within BPDT or S-BPDT.
582 static struct bpdt_entry
*__find_entry_by_type(struct bpdt_entry
*e
,
583 size_t count
, int type
)
586 for (i
= 0; i
< count
; i
++) {
587 if (e
[i
].type
== type
)
597 static struct bpdt_entry
*find_entry_by_type(int type
)
599 struct bpdt
*b
= buffer_get(&ifwi_image
.bpdt
);
603 struct bpdt_entry
*curr
= __find_entry_by_type(&b
->e
[0],
604 b
->h
.descriptor_count
,
610 b
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
614 return __find_entry_by_type(&b
->e
[0], b
->h
.descriptor_count
, type
);
618 * Find sub-partition type given its name. If the name does not exist, returns
621 static int find_type_by_name(const char *name
)
625 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
626 if ((strlen(subparts
[i
].name
) == strlen(name
)) &&
627 (!strcmp(subparts
[i
].name
, name
)))
631 if (i
== MAX_SUBPARTS
) {
632 ERROR("Invalid sub-partition name %s.\n", name
);
640 * Read the content of a sub-partition from input file and store it in
641 * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
643 * Returns the maximum offset occupied by the sub-partitions.
645 static size_t read_subpart_buf(void *data
, size_t size
, struct bpdt_entry
*e
,
650 size_t max_offset
= 0;
652 for (i
= 0; i
< count
; i
++) {
655 if (type
>= MAX_SUBPARTS
) {
656 ERROR("Invalid sub-partition type %zd.\n", type
);
660 if (buffer_size(&ifwi_image
.subpart_buf
[type
])) {
661 ERROR("Multiple sub-partitions of type %zd(%s).\n",
662 type
, subparts
[type
].name
);
666 if (e
[i
].size
== 0) {
667 INFO("Dummy sub-partition %zd(%s). Skipping.\n", type
,
668 subparts
[type
].name
);
672 assert((e
[i
].offset
+ e
[i
].size
) <= size
);
675 * Sub-partitions in IFWI image are not in the same order as
676 * in BPDT entries. BPDT entires are in header_order whereas
677 * sub-partition offsets in the image are in pack_order.
679 if ((e
[i
].offset
+ e
[i
].size
) > max_offset
)
680 max_offset
= e
[i
].offset
+ e
[i
].size
;
683 * S-BPDT sub-partition contains information about all the
684 * non-critical sub-partitions. Thus, size of S-BPDT
685 * sub-partition equals size of S-BPDT plus size of all the
686 * non-critical sub-partitions. Thus, reading whole of S-BPDT
687 * here would be redundant as the non-critical partitions are
688 * read and allocated buffers separately. Also, S-BPDT requires
689 * special handling for reading header and entries.
691 if (type
== S_BPDT_TYPE
)
694 buf
= &ifwi_image
.subpart_buf
[type
];
696 alloc_buffer(buf
, e
[i
].size
, subparts
[type
].name
);
697 memcpy(buffer_get(buf
), (uint8_t *)data
+ e
[i
].offset
,
706 * Allocate buffer for bpdt header, entries and all sub-partition content.
707 * Returns offset in data where BPDT ends.
709 static size_t alloc_bpdt_buffer(void *data
, size_t size
, size_t offset
,
710 struct buffer
*b
, const char *name
)
712 struct bpdt_header bpdt_header
;
713 assert((offset
+ BPDT_HEADER_SIZE
) < size
);
714 bpdt_read_header((uint8_t *)data
+ offset
, &bpdt_header
, name
);
716 /* Buffer to read BPDT header and entries. */
717 alloc_buffer(b
, get_bpdt_size(&bpdt_header
), name
);
719 struct bpdt
*bpdt
= buffer_get(b
);
720 memcpy(&bpdt
->h
, &bpdt_header
, BPDT_HEADER_SIZE
);
723 * If no entries are present, maximum offset occupied is (offset +
726 if (bpdt
->h
.descriptor_count
== 0)
727 return (offset
+ BPDT_HEADER_SIZE
);
729 /* Read all entries. */
730 assert((offset
+ get_bpdt_size(&bpdt
->h
)) < size
);
731 bpdt_read_entries((uint8_t *)data
+ offset
+ BPDT_HEADER_SIZE
, bpdt
,
734 /* Read all sub-partition content in subpart_buf. */
735 return read_subpart_buf(data
, size
, &bpdt
->e
[0],
736 bpdt
->h
.descriptor_count
);
739 static void parse_sbpdt(void *data
, size_t size
)
741 struct bpdt_entry
*s
;
742 s
= find_entry_by_type(S_BPDT_TYPE
);
746 assert(size
> s
->offset
);
748 alloc_bpdt_buffer(data
, size
, s
->offset
,
749 &ifwi_image
.subpart_buf
[S_BPDT_TYPE
],
753 static uint8_t calc_checksum(struct subpart_dir
*s
)
755 size_t size
= subpart_dir_size(&s
->h
);
756 uint8_t *data
= (uint8_t *)s
;
757 uint8_t checksum
= 0;
760 uint8_t old_checksum
= s
->h
.checksum
;
763 for (i
= 0; i
< size
; i
++)
766 s
->h
.checksum
= old_checksum
;
772 static void validate_subpart_dir(struct subpart_dir
*s
, const char *name
,
775 if ((s
->h
.marker
!= SUBPART_DIR_MARKER
) ||
776 (s
->h
.header_version
!= SUBPART_DIR_HEADER_VERSION_SUPPORTED
) ||
777 (s
->h
.entry_version
!= SUBPART_DIR_ENTRY_VERSION_SUPPORTED
) ||
778 (s
->h
.header_length
!= SUBPART_DIR_HEADER_SIZE
)) {
779 ERROR("Invalid subpart_dir for %s.\n", name
);
783 if (checksum_check
== false)
786 uint8_t checksum
= calc_checksum(s
);
788 if (checksum
!= s
->h
.checksum
)
789 ERROR("Invalid checksum for %s (Expected=0x%x, Actual=0x%x).\n",
790 name
, checksum
, s
->h
.checksum
);
793 static void validate_subpart_dir_without_checksum(struct subpart_dir
*s
,
796 validate_subpart_dir(s
, name
, 0);
799 static void validate_subpart_dir_with_checksum(struct subpart_dir
*s
,
802 validate_subpart_dir(s
, name
, 1);
805 static void parse_subpart_dir(struct buffer
*subpart_dir_buf
,
806 struct buffer
*input_buf
, const char *name
)
808 struct subpart_dir_header hdr
;
810 uint8_t *data
= buffer_get(input_buf
);
811 size_t size
= buffer_size(input_buf
);
813 /* Read Subpart_Dir header. */
814 assert(size
>= SUBPART_DIR_HEADER_SIZE
);
815 offset
= read_member(data
, offset
, sizeof(hdr
.marker
), &hdr
.marker
);
816 offset
= read_member(data
, offset
, sizeof(hdr
.num_entries
),
818 offset
= read_member(data
, offset
, sizeof(hdr
.header_version
),
819 &hdr
.header_version
);
820 offset
= read_member(data
, offset
, sizeof(hdr
.entry_version
),
822 offset
= read_member(data
, offset
, sizeof(hdr
.header_length
),
824 offset
= read_member(data
, offset
, sizeof(hdr
.checksum
), &hdr
.checksum
);
825 memcpy(hdr
.name
, data
+ offset
, sizeof(hdr
.name
));
826 offset
+= sizeof(hdr
.name
);
828 validate_subpart_dir_without_checksum((struct subpart_dir
*)&hdr
, name
);
830 assert(size
> subpart_dir_size(&hdr
));
831 alloc_buffer(subpart_dir_buf
, subpart_dir_size(&hdr
), "Subpart Dir");
832 memcpy(buffer_get(subpart_dir_buf
), &hdr
, SUBPART_DIR_HEADER_SIZE
);
834 /* Read Subpart Dir entries. */
835 struct subpart_dir
*subpart_dir
= buffer_get(subpart_dir_buf
);
836 struct subpart_dir_entry
*e
= &subpart_dir
->e
[0];
838 for (i
= 0; i
< hdr
.num_entries
; i
++) {
839 memcpy(e
[i
].name
, data
+ offset
, sizeof(e
[i
].name
));
840 offset
+= sizeof(e
[i
].name
);
841 offset
= read_member(data
, offset
, sizeof(e
[i
].offset
),
843 offset
= read_member(data
, offset
, sizeof(e
[i
].length
),
845 offset
= read_member(data
, offset
, sizeof(e
[i
].rsvd
),
849 validate_subpart_dir_with_checksum(subpart_dir
, name
);
851 print_subpart_dir(subpart_dir
);
854 /* Parse input image file to identify different sub-partitions. */
855 static int ifwi_parse(void)
857 DEBUG("Parsing IFWI image...\n");
858 const char *image_name
= param
.image_name
;
860 /* Read input file. */
861 struct buffer
*buff
= &ifwi_image
.input_buff
;
862 if (buffer_from_file(buff
, image_name
)) {
863 ERROR("Failed to read input file %s.\n", image_name
);
867 INFO("Buffer %p size 0x%zx\n", buff
->data
, buff
->size
);
869 /* Look for BPDT signature at 4K intervals. */
871 void *data
= buffer_get(buff
);
873 while (offset
< buffer_size(buff
)) {
874 if (read_at_le32(data
, offset
) == BPDT_SIGNATURE
)
879 if (offset
>= buffer_size(buff
)) {
880 ERROR("Image does not contain BPDT!!\n");
884 ifwi_image
.input_ifwi_start_offset
= offset
;
885 INFO("BPDT starts at offset 0x%zx.\n", offset
);
887 data
= (uint8_t *)data
+ offset
;
888 size_t ifwi_size
= buffer_size(buff
) - offset
;
890 /* Read BPDT and sub-partitions. */
891 uintptr_t end_offset
;
892 end_offset
= ifwi_image
.input_ifwi_start_offset
+
893 alloc_bpdt_buffer(data
, ifwi_size
, 0, &ifwi_image
.bpdt
, "BPDT");
895 /* Parse S-BPDT, if any. */
896 parse_sbpdt(data
, ifwi_size
);
899 * Store end offset of IFWI. Required for copying any trailing non-IFWI
901 * ASSUMPTION: IFWI image always ends on a 4K boundary.
903 ifwi_image
.input_ifwi_end_offset
= ALIGN(end_offset
, 4 * KiB
);
904 DEBUG("Parsing done.\n");
910 * This function is used by repack to count the number of BPDT and S-BPDT
911 * entries that are present. It frees the current buffers used by the entries
912 * and allocates fresh buffers that can be used for repacking. Returns BPDT
913 * entries which are empty and need to be filled in.
915 static void __bpdt_reset(struct buffer
*b
, size_t count
, size_t size
)
917 size_t bpdt_size
= BPDT_HEADER_SIZE
+ count
* BPDT_ENTRY_SIZE
;
918 assert(size
>= bpdt_size
);
921 * If buffer does not have the required size, allocate a fresh buffer.
923 if (buffer_size(b
) != size
) {
925 alloc_buffer(&temp
, size
, b
->name
);
926 memcpy(buffer_get(&temp
), buffer_get(b
), buffer_size(b
));
931 struct bpdt
*bpdt
= buffer_get(b
);
932 uint8_t *ptr
= (uint8_t *)&bpdt
->e
[0];
933 size_t entries_size
= BPDT_ENTRY_SIZE
* count
;
935 /* Zero out BPDT entries. */
936 memset(ptr
, 0, entries_size
);
937 /* Fill any pad-space with FF. */
938 memset(ptr
+ entries_size
, 0xFF, size
- bpdt_size
);
940 bpdt
->h
.descriptor_count
= count
;
943 static void bpdt_reset(void)
946 size_t bpdt_count
= 0, sbpdt_count
= 0, dummy_bpdt_count
= 0;
948 /* Count number of BPDT and S-BPDT entries. */
949 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
950 if (buffer_size(&ifwi_image
.subpart_buf
[i
]) == 0) {
951 if (subparts
[i
].attr
& MANDATORY_BPDT_ENTRY
) {
958 if (subparts
[i
].attr
& NON_CRITICAL_SUBPART
)
964 DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count
,
965 dummy_bpdt_count
, sbpdt_count
);
967 /* Update BPDT if required. */
968 size_t bpdt_size
= MAX(BPDT_MIN_SIZE
,
969 BPDT_HEADER_SIZE
+ bpdt_count
* BPDT_ENTRY_SIZE
);
970 __bpdt_reset(&ifwi_image
.bpdt
, bpdt_count
, bpdt_size
);
972 /* Update S-BPDT if required. */
973 bpdt_size
= ALIGN(BPDT_HEADER_SIZE
+ sbpdt_count
* BPDT_ENTRY_SIZE
,
975 __bpdt_reset(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
], sbpdt_count
,
979 /* Initialize BPDT entries in header order. */
980 static void bpdt_entries_init_header_order(void)
985 struct bpdt
*bpdt
, *sbpdt
, *curr
;
986 size_t bpdt_curr
= 0, sbpdt_curr
= 0, *count_ptr
;
988 bpdt
= buffer_get(&ifwi_image
.bpdt
);
989 sbpdt
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
991 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
992 type
= bpdt_header_order
[i
];
993 size
= buffer_size(&ifwi_image
.subpart_buf
[type
]);
995 if ((size
== 0) && !(subparts
[type
].attr
&
996 MANDATORY_BPDT_ENTRY
))
999 if (subparts
[type
].attr
& NON_CRITICAL_SUBPART
) {
1001 count_ptr
= &sbpdt_curr
;
1004 count_ptr
= &bpdt_curr
;
1007 assert(*count_ptr
< curr
->h
.descriptor_count
);
1008 curr
->e
[*count_ptr
].type
= type
;
1009 curr
->e
[*count_ptr
].flags
= 0;
1010 curr
->e
[*count_ptr
].offset
= 0;
1011 curr
->e
[*count_ptr
].size
= size
;
1017 static void pad_buffer(struct buffer
*b
, size_t size
)
1019 size_t buff_size
= buffer_size(b
);
1021 assert(buff_size
<= size
);
1023 if (buff_size
== size
)
1027 alloc_buffer(&temp
, size
, b
->name
);
1028 uint8_t *data
= buffer_get(&temp
);
1030 memcpy(data
, buffer_get(b
), buff_size
);
1031 memset(data
+ buff_size
, 0xFF, size
- buff_size
);
1036 /* Initialize offsets of entries using pack order. */
1037 static void bpdt_entries_init_pack_order(void)
1040 struct bpdt_entry
*curr
;
1041 size_t curr_offset
, curr_end
;
1043 curr_offset
= MAX(BPDT_MIN_SIZE
, buffer_size(&ifwi_image
.bpdt
));
1046 * There are two types of sub-partitions that need to be handled here:
1047 * 1. Sub-partitions that lie within the same 4K as BPDT
1048 * 2. Sub-partitions that lie outside the 4K of BPDT
1050 * For sub-partitions of type # 1, there is no requirement on the start
1051 * or end of the sub-partition. They need to be packed in without any
1052 * holes left in between. If there is any empty space left after the end
1053 * of the last sub-partition in 4K of BPDT, then that space needs to be
1054 * padded with FF bytes, but the size of the last sub-partition remains
1057 * For sub-partitions of type # 2, both the start and end should be a
1058 * multiple of 4K. If not, then it needs to be padded with FF bytes and
1059 * size adjusted such that the sub-partition ends on 4K boundary.
1062 /* #1 Sub-partitions that lie within same 4K as BPDT. */
1063 struct buffer
*last_bpdt_buff
= &ifwi_image
.bpdt
;
1065 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1066 type
= bpdt_pack_order
[i
];
1067 curr
= find_entry_by_type(type
);
1069 if ((curr
== NULL
) || (curr
->size
== 0))
1072 if (!(subparts
[type
].attr
& LIES_WITHIN_BPDT_4K
))
1075 curr
->offset
= curr_offset
;
1076 curr_offset
= curr
->offset
+ curr
->size
;
1077 last_bpdt_buff
= &ifwi_image
.subpart_buf
[type
];
1078 DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, "
1079 "curr->size=0x%x, buff_size=0x%zx\n", type
, curr_offset
,
1080 curr
->offset
, curr
->size
,
1081 buffer_size(&ifwi_image
.subpart_buf
[type
]));
1084 /* Pad ff bytes if there is any empty space left in BPDT 4K. */
1085 curr_end
= ALIGN(curr_offset
, 4 * KiB
);
1086 pad_buffer(last_bpdt_buff
,
1087 buffer_size(last_bpdt_buff
) + (curr_end
- curr_offset
));
1088 curr_offset
= curr_end
;
1090 /* #2 Sub-partitions that lie outside of BPDT 4K. */
1091 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1092 type
= bpdt_pack_order
[i
];
1093 curr
= find_entry_by_type(type
);
1095 if ((curr
== NULL
) || (curr
->size
== 0))
1098 if (subparts
[type
].attr
& LIES_WITHIN_BPDT_4K
)
1101 assert(curr_offset
== ALIGN(curr_offset
, 4 * KiB
));
1102 curr
->offset
= curr_offset
;
1103 curr_end
= ALIGN(curr
->offset
+ curr
->size
, 4 * KiB
);
1104 curr
->size
= curr_end
- curr
->offset
;
1106 pad_buffer(&ifwi_image
.subpart_buf
[type
], curr
->size
);
1108 curr_offset
= curr_end
;
1109 DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, "
1110 "curr->size=0x%x, buff_size=0x%zx\n", type
, curr_offset
,
1111 curr
->offset
, curr
->size
,
1112 buffer_size(&ifwi_image
.subpart_buf
[type
]));
1116 * Update size of S-BPDT to include size of all non-critical
1119 * Assumption: S-BPDT always lies at the end of IFWI image.
1121 curr
= find_entry_by_type(S_BPDT_TYPE
);
1124 assert(curr_offset
== ALIGN(curr_offset
, 4 * KiB
));
1125 curr
->size
= curr_offset
- curr
->offset
;
1128 /* Convert all members of BPDT to little-endian format. */
1129 static void bpdt_fixup_write_buffer(struct buffer
*buf
)
1131 struct bpdt
*s
= buffer_get(buf
);
1133 struct bpdt_header
*h
= &s
->h
;
1134 struct bpdt_entry
*e
= &s
->e
[0];
1136 size_t count
= h
->descriptor_count
;
1140 offset
= fix_member(&h
->signature
, offset
, sizeof(h
->signature
));
1141 offset
= fix_member(&h
->descriptor_count
, offset
,
1142 sizeof(h
->descriptor_count
));
1143 offset
= fix_member(&h
->bpdt_version
, offset
, sizeof(h
->bpdt_version
));
1144 offset
= fix_member(&h
->xor_redundant_block
, offset
,
1145 sizeof(h
->xor_redundant_block
));
1146 offset
= fix_member(&h
->ifwi_version
, offset
, sizeof(h
->ifwi_version
));
1147 offset
= fix_member(&h
->fit_tool_version
, offset
,
1148 sizeof(h
->fit_tool_version
));
1151 for (i
= 0; i
< count
; i
++) {
1152 offset
= fix_member(&e
[i
].type
, offset
, sizeof(e
[i
].type
));
1153 offset
= fix_member(&e
[i
].flags
, offset
, sizeof(e
[i
].flags
));
1154 offset
= fix_member(&e
[i
].offset
, offset
, sizeof(e
[i
].offset
));
1155 offset
= fix_member(&e
[i
].size
, offset
, sizeof(e
[i
].size
));
1159 /* Write BPDT to output buffer after fixup. */
1160 static void bpdt_write(struct buffer
*dst
, size_t offset
, struct buffer
*src
)
1162 bpdt_fixup_write_buffer(src
);
1163 memcpy(buffer_get(dst
) + offset
, buffer_get(src
), buffer_size(src
));
1167 * Follows these steps to re-create image:
1168 * 1. Write any non-IFWI prefix.
1169 * 2. Write out BPDT header and entries.
1170 * 3. Write sub-partition buffers to respective offsets.
1171 * 4. Write any non-IFWI suffix.
1173 * While performing the above steps, make sure that any empty holes are filled
1176 static void ifwi_write(const char *image_name
)
1178 struct bpdt_entry
*s
= find_entry_by_type(S_BPDT_TYPE
);
1181 size_t ifwi_start
, ifwi_end
, file_end
;
1183 ifwi_start
= ifwi_image
.input_ifwi_start_offset
;
1184 ifwi_end
= ifwi_start
+ ALIGN(s
->offset
+ s
->size
, 4 * KiB
);
1185 file_end
= ifwi_end
+ (buffer_size(&ifwi_image
.input_buff
) -
1186 ifwi_image
.input_ifwi_end_offset
);
1190 alloc_buffer(&b
, file_end
, "Final-IFWI");
1192 uint8_t *input_data
= buffer_get(&ifwi_image
.input_buff
);
1193 uint8_t *output_data
= buffer_get(&b
);
1195 DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start
,
1196 ifwi_end
, file_end
);
1198 /* Copy non-IFWI prefix, if any. */
1199 memcpy(output_data
, input_data
, ifwi_start
);
1201 DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start
);
1204 buffer_splice(&ifwi
, &b
, ifwi_start
, ifwi_end
- ifwi_start
);
1205 uint8_t *ifwi_data
= buffer_get(&ifwi
);
1207 /* Copy sub-partitions using pack_order. */
1208 struct bpdt_entry
*curr
;
1209 struct buffer
*subpart_buf
;
1211 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1212 type
= bpdt_pack_order
[i
];
1214 if (type
== S_BPDT_TYPE
)
1217 curr
= find_entry_by_type(type
);
1219 if ((curr
== NULL
) || (curr
->size
== 0))
1222 subpart_buf
= &ifwi_image
.subpart_buf
[type
];
1224 DEBUG("curr->offset=0x%x, curr->size=0x%x, type=%d, "
1225 "write_size=0x%zx\n", curr
->offset
, curr
->size
, type
,
1226 buffer_size(subpart_buf
));
1228 assert((curr
->offset
+ buffer_size(subpart_buf
)) <=
1229 buffer_size(&ifwi
));
1231 memcpy(ifwi_data
+ curr
->offset
, buffer_get(subpart_buf
),
1232 buffer_size(subpart_buf
));
1235 /* Copy non-IFWI suffix, if any. */
1236 if (ifwi_end
!= file_end
) {
1237 memcpy(output_data
+ ifwi_end
,
1238 input_data
+ ifwi_image
.input_ifwi_end_offset
,
1239 file_end
- ifwi_end
);
1240 DEBUG("Copied non-IFWI suffix (offset=0x%zx,size=0x%zx).\n",
1241 ifwi_end
, file_end
- ifwi_end
);
1245 * Convert BPDT to little-endian format and write it to output buffer.
1246 * S-BPDT is written first and then BPDT.
1248 bpdt_write(&ifwi
, s
->offset
, &ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
1249 bpdt_write(&ifwi
, 0, &ifwi_image
.bpdt
);
1251 if (buffer_write_file(&b
, image_name
)) {
1252 ERROR("File write error\n");
1257 printf("Image written successfully to %s.\n", image_name
);
1261 * Calculate size and offset of each sub-partition again since it might have
1262 * changed because of add/delete operation. Also, re-create BPDT and S-BPDT
1263 * entries and write back the new IFWI image to file.
1265 static void ifwi_repack(void)
1268 bpdt_entries_init_header_order();
1269 bpdt_entries_init_pack_order();
1271 struct bpdt
*b
= buffer_get(&ifwi_image
.bpdt
);
1272 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "BPDT");
1274 b
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
1275 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "S-BPDT");
1277 DEBUG("Repack done.. writing image.\n");
1278 ifwi_write(param
.image_name
);
1281 static void init_subpart_dir_header(struct subpart_dir_header
*hdr
,
1282 size_t count
, const char *name
)
1284 memset(hdr
, 0, sizeof(*hdr
));
1286 hdr
->marker
= SUBPART_DIR_MARKER
;
1287 hdr
->num_entries
= count
;
1288 hdr
->header_version
= SUBPART_DIR_HEADER_VERSION_SUPPORTED
;
1289 hdr
->entry_version
= SUBPART_DIR_ENTRY_VERSION_SUPPORTED
;
1290 hdr
->header_length
= SUBPART_DIR_HEADER_SIZE
;
1291 memcpy(hdr
->name
, name
, sizeof(hdr
->name
));
1294 static size_t init_subpart_dir_entry(struct subpart_dir_entry
*e
,
1295 struct buffer
*b
, size_t offset
)
1297 memset(e
, 0, sizeof(*e
));
1299 assert(strlen(b
->name
) <= sizeof(e
->name
));
1300 strncpy((char *)e
->name
, (char *)b
->name
, sizeof(e
->name
));
1302 e
->length
= buffer_size(b
);
1304 return (offset
+ buffer_size(b
));
1307 static void init_manifest_header(struct manifest_header
*hdr
, size_t size
)
1309 memset(hdr
, 0, sizeof(*hdr
));
1311 hdr
->header_type
= 0x4;
1312 assert((MANIFEST_HDR_SIZE
% DWORD_SIZE
) == 0);
1313 hdr
->header_length
= MANIFEST_HDR_SIZE
/ DWORD_SIZE
;
1314 hdr
->header_version
= 0x10000;
1315 hdr
->vendor
= 0x8086;
1317 struct tm
*local_time
;
1321 curr_time
= time(NULL
);
1322 local_time
= localtime(&curr_time
);
1323 strftime(buffer
, sizeof(buffer
), "0x%Y%m%d", local_time
);
1324 hdr
->date
= strtoul(buffer
, NULL
, 16);
1326 assert((size
% DWORD_SIZE
) == 0);
1327 hdr
->size
= size
/ DWORD_SIZE
;
1328 hdr
->id
= MANIFEST_ID_MAGIC
;
1331 static void init_signed_pkg_info_ext(struct signed_pkg_info_ext
*ext
,
1332 size_t count
, const char *name
)
1334 memset(ext
, 0, sizeof(*ext
));
1336 ext
->ext_type
= SIGNED_PKG_INFO_EXT_TYPE
;
1337 ext
->ext_length
= SIGNED_PKG_INFO_EXT_SIZE
+ count
* MODULE_SIZE
;
1338 memcpy(ext
->name
, name
, sizeof(ext
->name
));
1341 static void subpart_dir_fixup_write_buffer(struct buffer
*buf
)
1343 struct subpart_dir
*s
= buffer_get(buf
);
1344 struct subpart_dir_header
*h
= &s
->h
;
1345 struct subpart_dir_entry
*e
= &s
->e
[0];
1347 size_t count
= h
->num_entries
;
1350 offset
= fix_member(&h
->marker
, offset
, sizeof(h
->marker
));
1351 offset
= fix_member(&h
->num_entries
, offset
, sizeof(h
->num_entries
));
1352 offset
= fix_member(&h
->header_version
, offset
,
1353 sizeof(h
->header_version
));
1354 offset
= fix_member(&h
->entry_version
, offset
,
1355 sizeof(h
->entry_version
));
1356 offset
= fix_member(&h
->header_length
, offset
,
1357 sizeof(h
->header_length
));
1358 offset
= fix_member(&h
->checksum
, offset
, sizeof(h
->checksum
));
1359 offset
+= sizeof(h
->name
);
1362 for (i
= 0; i
< count
; i
++) {
1363 offset
+= sizeof(e
[i
].name
);
1364 offset
= fix_member(&e
[i
].offset
, offset
, sizeof(e
[i
].offset
));
1365 offset
= fix_member(&e
[i
].length
, offset
, sizeof(e
[i
].length
));
1366 offset
= fix_member(&e
[i
].rsvd
, offset
, sizeof(e
[i
].rsvd
));
1370 static void create_subpart(struct buffer
*dst
, struct buffer
*info
[],
1371 size_t count
, const char *name
)
1373 struct buffer subpart_dir_buff
;
1374 size_t size
= SUBPART_DIR_HEADER_SIZE
+ count
* SUBPART_DIR_ENTRY_SIZE
;
1376 alloc_buffer(&subpart_dir_buff
, size
, "subpart-dir");
1378 struct subpart_dir_header
*h
= buffer_get(&subpart_dir_buff
);
1379 struct subpart_dir_entry
*e
= (struct subpart_dir_entry
*)(h
+ 1);
1381 init_subpart_dir_header(h
, count
, name
);
1383 size_t curr_offset
= size
;
1386 for (i
= 0; i
< count
; i
++) {
1387 curr_offset
= init_subpart_dir_entry(&e
[i
], info
[i
],
1391 alloc_buffer(dst
, curr_offset
, name
);
1392 uint8_t *data
= buffer_get(dst
);
1394 for (i
= 0; i
< count
; i
++) {
1395 memcpy(data
+ e
[i
].offset
, buffer_get(info
[i
]),
1396 buffer_size(info
[i
]));
1399 h
->checksum
= calc_checksum(buffer_get(&subpart_dir_buff
));
1401 struct subpart_dir
*dir
= buffer_get(&subpart_dir_buff
);
1403 print_subpart_dir(dir
);
1405 subpart_dir_fixup_write_buffer(&subpart_dir_buff
);
1406 memcpy(data
, dir
, buffer_size(&subpart_dir_buff
));
1408 buffer_delete(&subpart_dir_buff
);
1411 static enum ifwi_ret
ibbp_dir_add(int type
)
1413 #define DUMMY_IBB_SIZE (4 * KiB)
1415 assert(type
== IBB_TYPE
);
1418 * Entry # 1 - IBBP.man
1419 * Contains manifest header and signed pkg info extension.
1421 struct buffer manifest
;
1422 size_t size
= MANIFEST_HDR_SIZE
+ SIGNED_PKG_INFO_EXT_SIZE
;
1423 alloc_buffer(&manifest
, size
, "IBBP.man");
1425 struct manifest_header
*man_hdr
= buffer_get(&manifest
);
1426 init_manifest_header(man_hdr
, size
);
1428 struct signed_pkg_info_ext
*ext
;
1429 ext
= (struct signed_pkg_info_ext
*)(man_hdr
+ 1);
1431 init_signed_pkg_info_ext(ext
, 0, subparts
[type
].name
);
1433 /* Entry # 2 - IBBL */
1435 if (buffer_from_file(&ibbl
, param
.file_name
))
1438 /* Entry # 3 - IBB */
1440 alloc_buffer(&ibb
, DUMMY_IBB_SIZE
, "IBB");
1441 memset(buffer_get(&ibb
), 0xFF, DUMMY_IBB_SIZE
);
1443 /* Create subpartition. */
1444 struct buffer
*info
[] = {
1445 &manifest
, &ibbl
, &ibb
,
1447 create_subpart(&ifwi_image
.subpart_buf
[type
], &info
[0],
1448 ARRAY_SIZE(info
), subparts
[type
].name
);
1450 return REPACK_REQUIRED
;
1453 static enum ifwi_ret
ifwi_raw_add(int type
)
1455 if (buffer_from_file(&ifwi_image
.subpart_buf
[type
], param
.file_name
))
1458 printf("Sub-partition %s(%d) added from file %s.\n", param
.subpart_name
,
1459 type
, param
.file_name
);
1460 return REPACK_REQUIRED
;
1463 static enum ifwi_ret
ifwi_dir_add(int type
)
1465 if (!(subparts
[type
].attr
& CONTAINS_DIR
) ||
1466 (subparts
[type
].dir_ops
.dir_add
== NULL
)) {
1467 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1468 subparts
[type
].name
, type
);
1472 if (!param
.dentry_name
) {
1473 ERROR("%s: -e option required\n", __func__
);
1477 enum ifwi_ret ret
= subparts
[type
].dir_ops
.dir_add(type
);
1478 if (ret
!= COMMAND_ERR
)
1479 printf("Sub-partition %s(%d) entry %s added from file %s.\n",
1480 param
.subpart_name
, type
, param
.dentry_name
,
1483 ERROR("Sub-partition dir operation failed.\n");
1488 static enum ifwi_ret
ifwi_add(void)
1490 if (!param
.file_name
) {
1491 ERROR("%s: -f option required\n", __func__
);
1495 if (!param
.subpart_name
) {
1496 ERROR("%s: -n option required\n", __func__
);
1500 int type
= find_type_by_name(param
.subpart_name
);
1504 const struct subpart_info
*curr_subpart
= &subparts
[type
];
1506 if (curr_subpart
->attr
& AUTO_GENERATED
) {
1507 ERROR("Cannot add auto-generated sub-partitions.\n");
1511 if (buffer_size(&ifwi_image
.subpart_buf
[type
])) {
1512 ERROR("Image already contains sub-partition %s(%d).\n",
1513 param
.subpart_name
, type
);
1518 return ifwi_dir_add(type
);
1520 return ifwi_raw_add(type
);
1523 static enum ifwi_ret
ifwi_delete(void)
1525 if (!param
.subpart_name
) {
1526 ERROR("%s: -n option required\n", __func__
);
1530 int type
= find_type_by_name(param
.subpart_name
);
1534 const struct subpart_info
*curr_subpart
= &subparts
[type
];
1536 if (curr_subpart
->attr
& AUTO_GENERATED
) {
1537 ERROR("Cannot delete auto-generated sub-partitions.\n");
1541 if (buffer_size(&ifwi_image
.subpart_buf
[type
]) == 0) {
1542 printf("Image does not contain sub-partition %s(%d).\n",
1543 param
.subpart_name
, type
);
1544 return NO_ACTION_REQUIRED
;
1547 buffer_delete(&ifwi_image
.subpart_buf
[type
]);
1548 printf("Sub-Partition %s(%d) deleted.\n", subparts
[type
].name
, type
);
1549 return REPACK_REQUIRED
;
1552 static enum ifwi_ret
ifwi_dir_extract(int type
)
1554 if (!(subparts
[type
].attr
& CONTAINS_DIR
)) {
1555 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1556 subparts
[type
].name
, type
);
1560 if (!param
.dentry_name
) {
1561 ERROR("%s: -e option required.\n", __func__
);
1565 struct buffer subpart_dir_buff
;
1566 parse_subpart_dir(&subpart_dir_buff
, &ifwi_image
.subpart_buf
[type
],
1567 subparts
[type
].name
);
1570 struct subpart_dir
*s
= buffer_get(&subpart_dir_buff
);
1572 for (i
= 0; i
< s
->h
.num_entries
; i
++) {
1573 if (!strncmp((char *)s
->e
[i
].name
, param
.dentry_name
,
1574 sizeof(s
->e
[i
].name
)))
1578 if (i
== s
->h
.num_entries
) {
1579 ERROR("Entry %s not found in subpartition for %s.\n",
1580 param
.dentry_name
, param
.subpart_name
);
1586 DEBUG("Splicing buffer at 0x%x size 0x%x\n", s
->e
[i
].offset
,
1588 buffer_splice(&dst
, &ifwi_image
.subpart_buf
[type
], s
->e
[i
].offset
,
1591 if (buffer_write_file(&dst
, param
.file_name
))
1594 printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1595 param
.subpart_name
, type
, param
.dentry_name
, param
.file_name
);
1597 return NO_ACTION_REQUIRED
;
1600 static enum ifwi_ret
ifwi_raw_extract(int type
)
1602 if (buffer_write_file(&ifwi_image
.subpart_buf
[type
], param
.file_name
))
1605 printf("Sub-Partition %s(%d) stored in %s.\n", param
.subpart_name
, type
,
1608 return NO_ACTION_REQUIRED
;
1611 static enum ifwi_ret
ifwi_extract(void)
1613 if (!param
.file_name
) {
1614 ERROR("%s: -f option required\n", __func__
);
1618 if (!param
.subpart_name
) {
1619 ERROR("%s: -n option required\n", __func__
);
1623 int type
= find_type_by_name(param
.subpart_name
);
1627 if (type
== S_BPDT_TYPE
) {
1628 INFO("Tool does not support raw extract for %s\n",
1629 param
.subpart_name
);
1630 return NO_ACTION_REQUIRED
;
1633 if (buffer_size(&ifwi_image
.subpart_buf
[type
]) == 0) {
1634 ERROR("Image does not contain sub-partition %s(%d).\n",
1635 param
.subpart_name
, type
);
1639 INFO("Extracting sub-partition %s(%d).\n", param
.subpart_name
, type
);
1641 return ifwi_dir_extract(type
);
1643 return ifwi_raw_extract(type
);
1646 static enum ifwi_ret
ifwi_print(void)
1650 struct bpdt
*b
= buffer_get(&ifwi_image
.bpdt
);
1652 bpdt_print_header(&b
->h
, "BPDT");
1653 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "BPDT");
1655 b
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
1656 bpdt_print_header(&b
->h
, "S-BPDT");
1657 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "S-BPDT");
1659 if (param
.dir_ops
== 0) {
1661 return NO_ACTION_REQUIRED
;
1665 struct buffer subpart_dir_buf
;
1666 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1667 if (!(subparts
[i
].attr
& CONTAINS_DIR
) ||
1668 (buffer_size(&ifwi_image
.subpart_buf
[i
]) == 0))
1671 parse_subpart_dir(&subpart_dir_buf
, &ifwi_image
.subpart_buf
[i
],
1673 buffer_delete(&subpart_dir_buf
);
1678 return NO_ACTION_REQUIRED
;
1681 static enum ifwi_ret
ifwi_raw_replace(int type
)
1683 buffer_delete(&ifwi_image
.subpart_buf
[type
]);
1684 return ifwi_raw_add(type
);
1687 static enum ifwi_ret
ifwi_dir_replace(int type
)
1689 if (!(subparts
[type
].attr
& CONTAINS_DIR
)) {
1690 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1691 subparts
[type
].name
, type
);
1695 if (!param
.dentry_name
) {
1696 ERROR("%s: -e option required.\n", __func__
);
1700 struct buffer subpart_dir_buf
;
1701 parse_subpart_dir(&subpart_dir_buf
, &ifwi_image
.subpart_buf
[type
],
1702 subparts
[type
].name
);
1705 struct subpart_dir
*s
= buffer_get(&subpart_dir_buf
);
1707 for (i
= 0; i
< s
->h
.num_entries
; i
++) {
1708 if (!strcmp((char *)s
->e
[i
].name
, param
.dentry_name
))
1712 if (i
== s
->h
.num_entries
) {
1713 ERROR("Entry %s not found in subpartition for %s.\n",
1714 param
.dentry_name
, param
.subpart_name
);
1719 if (buffer_from_file(&b
, param
.file_name
)) {
1720 ERROR("Failed to read %s\n", param
.file_name
);
1725 size_t dst_size
= buffer_size(&ifwi_image
.subpart_buf
[type
]) +
1726 buffer_size(&b
) - s
->e
[i
].length
;
1727 size_t subpart_start
= s
->e
[i
].offset
;
1728 size_t subpart_end
= s
->e
[i
].offset
+ s
->e
[i
].length
;
1730 alloc_buffer(&dst
, dst_size
, ifwi_image
.subpart_buf
[type
].name
);
1732 uint8_t *src_data
= buffer_get(&ifwi_image
.subpart_buf
[type
]);
1733 uint8_t *dst_data
= buffer_get(&dst
);
1734 size_t curr_offset
= 0;
1736 /* Copy data before the sub-partition entry. */
1737 memcpy(dst_data
+ curr_offset
, src_data
, subpart_start
);
1738 curr_offset
+= subpart_start
;
1740 /* Copy sub-partition entry. */
1741 memcpy(dst_data
+ curr_offset
, buffer_get(&b
), buffer_size(&b
));
1742 curr_offset
+= buffer_size(&b
);
1744 /* Copy remaining data. */
1745 memcpy(dst_data
+ curr_offset
, src_data
+ subpart_end
,
1746 buffer_size(&ifwi_image
.subpart_buf
[type
]) - subpart_end
);
1748 /* Update sub-partition buffer. */
1749 int offset
= s
->e
[i
].offset
;
1750 buffer_delete(&ifwi_image
.subpart_buf
[type
]);
1751 ifwi_image
.subpart_buf
[type
] = dst
;
1753 /* Update length of entry in the subpartition. */
1754 s
->e
[i
].length
= buffer_size(&b
);
1757 /* Adjust offsets of affected entries in subpartition. */
1758 offset
= s
->e
[i
].offset
- offset
;
1759 for (; i
< s
->h
.num_entries
; i
++) {
1760 s
->e
[i
].offset
+= offset
;
1763 /* Re-calculate checksum. */
1764 s
->h
.checksum
= calc_checksum(s
);
1766 /* Convert members to litte-endian. */
1767 subpart_dir_fixup_write_buffer(&subpart_dir_buf
);
1769 memcpy(dst_data
, buffer_get(&subpart_dir_buf
),
1770 buffer_size(&subpart_dir_buf
));
1772 buffer_delete(&subpart_dir_buf
);
1774 printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
1775 param
.subpart_name
, type
, param
.dentry_name
, param
.file_name
);
1777 return REPACK_REQUIRED
;
1780 static enum ifwi_ret
ifwi_replace(void)
1782 if (!param
.file_name
) {
1783 ERROR("%s: -f option required\n", __func__
);
1787 if (!param
.subpart_name
) {
1788 ERROR("%s: -n option required\n", __func__
);
1792 int type
= find_type_by_name(param
.subpart_name
);
1796 const struct subpart_info
*curr_subpart
= &subparts
[type
];
1798 if (curr_subpart
->attr
& AUTO_GENERATED
) {
1799 ERROR("Cannot replace auto-generated sub-partitions.\n");
1803 if (buffer_size(&ifwi_image
.subpart_buf
[type
]) == 0) {
1804 ERROR("Image does not contain sub-partition %s(%d).\n",
1805 param
.subpart_name
, type
);
1810 return ifwi_dir_replace(type
);
1812 return ifwi_raw_replace(type
);
1815 static enum ifwi_ret
ifwi_create(void)
1818 * Create peels off any non-IFWI content present in the input buffer and
1819 * creates output file with only the IFWI present.
1822 if (!param
.file_name
) {
1823 ERROR("%s: -f option required\n", __func__
);
1827 /* Peel off any non-IFWI prefix. */
1828 buffer_seek(&ifwi_image
.input_buff
,
1829 ifwi_image
.input_ifwi_start_offset
);
1830 /* Peel off any non-IFWI suffix. */
1831 buffer_set_size(&ifwi_image
.input_buff
,
1832 ifwi_image
.input_ifwi_end_offset
-
1833 ifwi_image
.input_ifwi_start_offset
);
1836 * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
1838 ifwi_image
.input_ifwi_end_offset
-= ifwi_image
.input_ifwi_start_offset
;
1839 ifwi_image
.input_ifwi_start_offset
= 0;
1841 param
.image_name
= param
.file_name
;
1843 return REPACK_REQUIRED
;
1848 const char *optstring
;
1849 enum ifwi_ret (*function
)(void);
1852 static const struct command commands
[] = {
1853 {"add", "f:n:e:dvh?", ifwi_add
},
1854 {"create", "f:vh?", ifwi_create
},
1855 {"delete", "f:n:vh?", ifwi_delete
},
1856 {"extract", "f:n:e:dvh?", ifwi_extract
},
1857 {"print", "dh?", ifwi_print
},
1858 {"replace", "f:n:e:dvh?", ifwi_replace
},
1861 static struct option long_options
[] = {
1862 {"subpart_dentry", required_argument
, 0, 'e'},
1863 {"file", required_argument
, 0, 'f'},
1864 {"help", required_argument
, 0, 'h'},
1865 {"name", required_argument
, 0, 'n'},
1866 {"dir_ops", no_argument
, 0, 'd'},
1867 {"verbose", no_argument
, 0, 'v'},
1871 static void usage(const char *name
)
1873 printf("ifwitool: Utility for IFWI manipulation\n\n"
1876 " %s FILE COMMAND [PARAMETERS]\n\n"
1878 " add -f FILE -n NAME [-d -e ENTRY]\n"
1881 " extract -f FILE -n NAME [-d -e ENTRY]\n"
1883 " replace -f FILE -n NAME [-d -e ENTRY]\n"
1885 " -f FILE : File to read/write/create/extract\n"
1886 " -d : Perform directory operation\n"
1887 " -e ENTRY: Name of directory entry to operate on\n"
1888 " -v : Verbose level\n"
1889 " -h : Help message\n"
1890 " -n NAME : Name of sub-partition to operate on\n",
1894 printf("\nNAME should be one of:\n");
1896 for (i
= 0; i
< MAX_SUBPARTS
; i
++)
1897 printf("%s(%s)\n", subparts
[i
].name
, subparts
[i
].readable_name
);
1901 int main(int argc
, char **argv
)
1908 param
.image_name
= argv
[1];
1909 char *cmd
= argv
[2];
1914 for (i
= 0; i
< ARRAY_SIZE(commands
); i
++) {
1915 if (strcmp(cmd
, commands
[i
].name
) != 0)
1923 c
= getopt_long(argc
, argv
, commands
[i
].optstring
,
1924 long_options
, &option_index
);
1929 /* Filter out illegal long options. */
1930 if (strchr(commands
[i
].optstring
, c
) == NULL
) {
1931 ERROR("%s: invalid option -- '%c'\n", argv
[0],
1938 param
.subpart_name
= optarg
;
1941 param
.file_name
= optarg
;
1947 param
.dentry_name
= optarg
;
1962 ERROR("%s: ifwi parsing failed\n", argv
[0]);
1966 enum ifwi_ret ret
= commands
[i
].function();
1968 if (ret
== COMMAND_ERR
) {
1969 ERROR("%s: failed execution\n", argv
[0]);
1973 if (ret
== REPACK_REQUIRED
)
1979 ERROR("%s: invalid command\n", argv
[0]);