1 /* ifwitool, CLI utility for IFWI manipulation */
2 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <commonlib/bsd/helpers.h>
5 #include <commonlib/endian.h>
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.
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.
21 * Both tables are identified by BPDT_SIGNATURE stored at the start of the
24 #define BPDT_SIGNATURE (0x000055AA)
29 /* Parameters passed in by caller. */
31 const char *file_name
;
32 size_t logical_boot_partition
;
33 const char *subpart_name
;
34 const char *image_name
;
36 const char *dentry_name
;
41 * This is used to identify start of BPDT. It should always be
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
;
56 #define BPDT_HEADER_SIZE (sizeof(struct bpdt_header))
59 /* Type of sub-partition. */
61 /* Attributes of sub-partition. */
63 /* Offset of sub-partition from beginning of LBP. */
65 /* Size in bytes of sub-partition. */
68 #define BPDT_ENTRY_SIZE (sizeof(struct bpdt_entry))
72 /* In practice, this could be an array of 0 to n entries. */
73 struct bpdt_entry e
[];
76 static inline size_t get_bpdt_size(struct bpdt_header
*h
)
78 return (sizeof(*h
) + BPDT_ENTRY_SIZE
* h
->descriptor_count
);
81 /* Minimum size in bytes allocated to BPDT in IFWI. */
82 #define BPDT_MIN_SIZE (512)
84 /* Header to define directory header for sub-partition. */
85 struct subpart_dir_header
{
86 /* Should be SUBPART_DIR_MARKER. */
88 /* Number of directory entries in the sub-partition. */
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
;
97 * 2s complement of 8-bit sum from first byte of header to last byte of
98 * last directory entry.
101 /* ASCII short name of sub-partition. */
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
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. */
114 /* Offset of entry from beginning of sub-partition. */
116 /* Length in bytes of sub-directory entry. */
121 #define SUBPART_DIR_ENTRY_SIZE \
122 (sizeof(struct subpart_dir_entry))
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
[];
130 static inline size_t subpart_dir_size(struct subpart_dir_header
*h
)
132 return (sizeof(*h
) + SUBPART_DIR_ENTRY_SIZE
* h
->num_entries
);
135 struct manifest_header
{
136 uint32_t header_type
;
137 uint32_t header_length
;
138 uint32_t header_version
;
149 uint32_t modulus_size
;
150 uint32_t exponent_size
;
151 uint8_t public_key
[256];
153 uint8_t signature
[256];
157 #define MANIFEST_HDR_SIZE (sizeof(struct manifest_header))
158 #define MANIFEST_ID_MAGIC (0x324e4d24)
165 uint32_t metadata_size
;
166 uint8_t metadata_hash
[32];
169 #define MODULE_SIZE (sizeof(struct module))
171 struct signed_pkg_info_ext
{
181 #define SIGNED_PKG_INFO_EXT_TYPE 0x15
182 #define SIGNED_PKG_INFO_EXT_SIZE \
183 (sizeof(struct signed_pkg_info_ext))
186 * Attributes for various IFWI sub-partitions.
187 * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
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.
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),
203 /* Type value for various IFWI sub-partitions. */
204 enum bpdt_entry_type
{
215 IFP_OVERRIDE_TYPE
= 10,
216 DEBUG_TOKENS_TYPE
= 11,
221 NVM_CONFIG_TYPE
= 16,
223 UFS_RATE_B_TYPE
= 18,
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.
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.
237 const enum bpdt_entry_type bpdt_header_order
[MAX_SUBPARTS
] = {
238 /* Order of the following entries is mandatory. */
245 /* Order of the following entries is recommended. */
261 const enum bpdt_entry_type bpdt_pack_order
[MAX_SUBPARTS
] = {
262 /* Order of the following entries is mandatory. */
269 /* Order of the following entries is recommended. */
285 /* Utility functions. */
288 NO_ACTION_REQUIRED
= 0,
293 enum ifwi_ret (*dir_add
)(int);
296 static enum ifwi_ret
ibbp_dir_add(int);
298 const struct subpart_info
{
300 const char *readable_name
;
302 struct dir_ops dir_ops
;
303 } subparts
[MAX_SUBPARTS
] = {
305 [SMIP_TYPE
] = {"SMIP", "SMIP", CONTAINS_DIR
, {NULL
} },
307 [CSE_RBE_TYPE
] = {"RBEP", "CSE_RBE", CONTAINS_DIR
|
308 MANDATORY_BPDT_ENTRY
, {NULL
} },
310 [CSE_BUP_TYPE
] = {"FTPR", "CSE_BUP", CONTAINS_DIR
|
311 MANDATORY_BPDT_ENTRY
, {NULL
} },
313 [UCODE_TYPE
] = {"UCOD", "Microcode", CONTAINS_DIR
, {NULL
} },
315 [IBB_TYPE
] = {"IBBP", "Bootblock", CONTAINS_DIR
, {ibbp_dir_add
} },
317 [S_BPDT_TYPE
] = {"S_BPDT", "S-BPDT", AUTO_GENERATED
|
318 MANDATORY_BPDT_ENTRY
, {NULL
} },
320 [OBB_TYPE
] = {"OBBP", "OEM boot block", CONTAINS_DIR
|
321 NON_CRITICAL_SUBPART
, {NULL
} },
323 [CSE_MAIN_TYPE
] = {"NFTP", "CSE_MAIN", CONTAINS_DIR
|
324 NON_CRITICAL_SUBPART
, {NULL
} },
326 [ISH_TYPE
] = {"ISHP", "ISH", NON_CRITICAL_SUBPART
, {NULL
} },
328 [CSE_IDLM_TYPE
] = {"DLMP", "CSE_IDLM", CONTAINS_DIR
|
329 MANDATORY_BPDT_ENTRY
, {NULL
} },
331 [IFP_OVERRIDE_TYPE
] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
332 LIES_WITHIN_BPDT_4K
| MANDATORY_BPDT_ENTRY
,
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
} },
340 [UFS_GPP_TYPE
] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K
|
341 MANDATORY_BPDT_ENTRY
, {NULL
} },
343 [PMC_TYPE
] = {"PMCP", "PMC firmware", CONTAINS_DIR
, {NULL
} },
345 [IUNIT_TYPE
] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART
, {NULL
} },
347 [NVM_CONFIG_TYPE
] = {"NVM_CONFIG", "NVM Config", 0, {NULL
} },
349 [UEP_TYPE
] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K
| MANDATORY_BPDT_ENTRY
,
351 /* UFS Rate B Config */
352 [UFS_RATE_B_TYPE
] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL
} },
356 /* Data read from input file. */
357 struct buffer input_buff
;
359 /* BPDT header and entries. */
361 size_t input_ifwi_start_offset
;
362 size_t input_ifwi_end_offset
;
364 /* Subpartition content. */
365 struct buffer subpart_buf
[MAX_SUBPARTS
];
368 static void alloc_buffer(struct buffer
*b
, size_t s
, const char *n
)
370 if (buffer_create(b
, s
, n
) == 0)
373 ERROR("Buffer allocation failure for %s (size = %zx).\n", n
, s
);
378 * Read header/entry members in little-endian format.
379 * Returns the offset up to which the read was performed.
381 static size_t read_member(void *src
, size_t offset
, size_t size_bytes
,
384 switch (size_bytes
) {
386 *(uint8_t *)dst
= read_at_le8(src
, offset
);
389 *(uint16_t *)dst
= read_at_le16(src
, offset
);
392 *(uint32_t *)dst
= read_at_le32(src
, offset
);
395 *(uint64_t *)dst
= read_at_le64(src
, offset
);
398 ERROR("Read size not supported %zd\n", size_bytes
);
402 return (offset
+ size_bytes
);
406 * Convert to little endian format.
407 * Returns the offset up to which the fixup was performed.
409 static size_t fix_member(void *data
, size_t offset
, size_t size_bytes
)
411 uint8_t *src
= (uint8_t *)data
+ offset
;
413 switch (size_bytes
) {
415 write_at_le8(data
, *(uint8_t *)src
, offset
);
418 write_at_le16(data
, *(uint16_t *)src
, offset
);
421 write_at_le32(data
, *(uint32_t *)src
, offset
);
424 write_at_le64(data
, *(uint64_t *)src
, offset
);
427 ERROR("Write size not supported %zd\n", size_bytes
);
430 return (offset
+ size_bytes
);
434 static void print_subpart_dir(struct subpart_dir
*s
)
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
]);
453 printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
456 printf("=============================================================="
457 "===========================================================\n");
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
,
465 printf("=============================================================="
466 "===========================================================\n");
469 static void bpdt_print_header(struct bpdt_header
*h
, const char *name
)
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
);
484 static void bpdt_print_entries(struct bpdt_entry
*e
, size_t count
,
490 printf("%s entries\n", name
);
492 printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
493 "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
496 printf("=============================================================="
497 "=============================================================="
498 "=============================================================="
499 "===============\n");
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
);
511 printf("=============================================================="
512 "=============================================================="
513 "=============================================================="
514 "===============\n");
518 static void bpdt_validate_header(struct bpdt_header
*h
, const char *name
)
520 assert(h
->signature
== BPDT_SIGNATURE
);
522 if (h
->bpdt_version
!= 1) {
523 ERROR("Invalid header : %s\n", name
);
527 DEBUG("Validated header : %s\n", name
);
530 static void bpdt_read_header(void *data
, struct bpdt_header
*h
,
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
),
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
),
544 read_member(data
, offset
, sizeof(h
->fit_tool_version
),
545 &h
->fit_tool_version
);
547 bpdt_validate_header(h
, name
);
548 bpdt_print_header(h
, name
);
551 static void bpdt_read_entries(void *data
, struct bpdt
*bpdt
, const char *name
)
553 size_t i
, offset
= 0;
554 struct bpdt_entry
*e
= &bpdt
->e
[0];
555 size_t count
= bpdt
->h
.descriptor_count
;
557 for (i
= 0; i
< count
; i
++) {
558 offset
= read_member(data
, offset
, sizeof(e
[i
].type
),
560 offset
= read_member(data
, offset
, sizeof(e
[i
].flags
),
562 offset
= read_member(data
, offset
, sizeof(e
[i
].offset
),
564 offset
= read_member(data
, offset
, sizeof(e
[i
].size
),
568 bpdt_print_entries(e
, count
, name
);
572 * Given type of sub-partition, identify BPDT entry for it.
573 * Sub-Partition could lie either within BPDT or S-BPDT.
575 static struct bpdt_entry
*__find_entry_by_type(struct bpdt_entry
*e
,
576 size_t count
, int type
)
579 for (i
= 0; i
< count
; i
++) {
580 if (e
[i
].type
== type
)
590 static struct bpdt_entry
*find_entry_by_type(int type
)
592 struct bpdt
*b
= buffer_get(&ifwi_image
.bpdt
);
596 struct bpdt_entry
*curr
= __find_entry_by_type(&b
->e
[0],
597 b
->h
.descriptor_count
,
603 b
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
607 return __find_entry_by_type(&b
->e
[0], b
->h
.descriptor_count
, type
);
611 * Find sub-partition type given its name. If the name does not exist, returns
614 static int find_type_by_name(const char *name
)
618 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
619 if ((strlen(subparts
[i
].name
) == strlen(name
)) &&
620 (!strcmp(subparts
[i
].name
, name
)))
624 if (i
== MAX_SUBPARTS
) {
625 ERROR("Invalid sub-partition name %s.\n", name
);
633 * Read the content of a sub-partition from input file and store it in
634 * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
636 * Returns the maximum offset occupied by the sub-partitions.
638 static size_t read_subpart_buf(void *data
, size_t size
, struct bpdt_entry
*e
,
643 size_t max_offset
= 0;
645 for (i
= 0; i
< count
; i
++) {
648 if (type
>= MAX_SUBPARTS
) {
649 ERROR("Invalid sub-partition type %zd.\n", type
);
653 if (buffer_size(&ifwi_image
.subpart_buf
[type
])) {
654 ERROR("Multiple sub-partitions of type %zd(%s).\n",
655 type
, subparts
[type
].name
);
659 if (e
[i
].size
== 0) {
660 INFO("Dummy sub-partition %zd(%s). Skipping.\n", type
,
661 subparts
[type
].name
);
665 assert((e
[i
].offset
+ e
[i
].size
) <= size
);
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.
672 if ((e
[i
].offset
+ e
[i
].size
) > max_offset
)
673 max_offset
= e
[i
].offset
+ e
[i
].size
;
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.
684 if (type
== S_BPDT_TYPE
)
687 buf
= &ifwi_image
.subpart_buf
[type
];
689 alloc_buffer(buf
, e
[i
].size
, subparts
[type
].name
);
690 memcpy(buffer_get(buf
), (uint8_t *)data
+ e
[i
].offset
,
699 * Allocate buffer for bpdt header, entries and all sub-partition content.
700 * Returns offset in data where BPDT ends.
702 static size_t alloc_bpdt_buffer(void *data
, size_t size
, size_t offset
,
703 struct buffer
*b
, const char *name
)
705 struct bpdt_header bpdt_header
;
706 assert((offset
+ BPDT_HEADER_SIZE
) < size
);
707 bpdt_read_header((uint8_t *)data
+ offset
, &bpdt_header
, name
);
709 /* Buffer to read BPDT header and entries. */
710 alloc_buffer(b
, get_bpdt_size(&bpdt_header
), name
);
712 struct bpdt
*bpdt
= buffer_get(b
);
713 memcpy(&bpdt
->h
, &bpdt_header
, BPDT_HEADER_SIZE
);
716 * If no entries are present, maximum offset occupied is (offset +
719 if (bpdt
->h
.descriptor_count
== 0)
720 return (offset
+ BPDT_HEADER_SIZE
);
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
,
727 /* Read all sub-partition content in subpart_buf. */
728 return read_subpart_buf(data
, size
, &bpdt
->e
[0],
729 bpdt
->h
.descriptor_count
);
732 static void parse_sbpdt(void *data
, size_t size
)
734 struct bpdt_entry
*s
;
735 s
= find_entry_by_type(S_BPDT_TYPE
);
739 assert(size
> s
->offset
);
741 alloc_bpdt_buffer(data
, size
, s
->offset
,
742 &ifwi_image
.subpart_buf
[S_BPDT_TYPE
],
746 static uint8_t calc_checksum(struct subpart_dir
*s
)
748 size_t size
= subpart_dir_size(&s
->h
);
749 uint8_t *data
= (uint8_t *)s
;
750 uint8_t checksum
= 0;
753 uint8_t old_checksum
= s
->h
.checksum
;
756 for (i
= 0; i
< size
; i
++)
759 s
->h
.checksum
= old_checksum
;
765 static void validate_subpart_dir(struct subpart_dir
*s
, const char *name
,
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
);
776 if (checksum_check
== false)
779 uint8_t checksum
= calc_checksum(s
);
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
);
786 static void validate_subpart_dir_without_checksum(struct subpart_dir
*s
,
789 validate_subpart_dir(s
, name
, 0);
792 static void validate_subpart_dir_with_checksum(struct subpart_dir
*s
,
795 validate_subpart_dir(s
, name
, 1);
798 static void parse_subpart_dir(struct buffer
*subpart_dir_buf
,
799 struct buffer
*input_buf
, const char *name
)
801 struct subpart_dir_header hdr
;
803 uint8_t *data
= buffer_get(input_buf
);
804 size_t size
= buffer_size(input_buf
);
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
),
811 offset
= read_member(data
, offset
, sizeof(hdr
.header_version
),
812 &hdr
.header_version
);
813 offset
= read_member(data
, offset
, sizeof(hdr
.entry_version
),
815 offset
= read_member(data
, offset
, sizeof(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
);
821 validate_subpart_dir_without_checksum((struct subpart_dir
*)&hdr
, name
);
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
);
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];
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
),
836 offset
= read_member(data
, offset
, sizeof(e
[i
].length
),
838 offset
= read_member(data
, offset
, sizeof(e
[i
].rsvd
),
842 validate_subpart_dir_with_checksum(subpart_dir
, name
);
844 print_subpart_dir(subpart_dir
);
847 /* Parse the bpdt entries to compute the size of the BPDT */
848 static size_t bpdt_size(void *data
)
850 struct bpdt
*b
= (struct bpdt
*)data
;
853 for (i
= 0; i
< b
->h
.descriptor_count
; i
++)
854 size
= MAX(size
, b
->e
[i
].offset
+ b
->e
[i
].size
);
859 /* Parse input image file to identify different sub-partitions. */
860 static int ifwi_parse(void)
862 DEBUG("Parsing IFWI image...\n");
863 const char *image_name
= param
.image_name
;
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
);
872 INFO("Buffer %p size 0x%zx\n", buff
->data
, buff
->size
);
874 /* Look for BPDT signature at 4K intervals. */
875 size_t offset
= 0, lbp
= LBP1
;
876 void *data
= buffer_get(buff
);
878 while (offset
< buffer_size(buff
)) {
879 if (read_at_le32(data
, offset
) == BPDT_SIGNATURE
) {
880 if (lbp
== param
.logical_boot_partition
)
882 offset
+= bpdt_size((uint8_t *)data
+ offset
);
888 if (offset
>= buffer_size(buff
)) {
889 ERROR("Image does not contain BPDT for LBP=%zd!!\n",
890 param
.logical_boot_partition
);
894 ifwi_image
.input_ifwi_start_offset
= offset
;
895 INFO("BPDT starts at offset 0x%zx.\n", offset
);
897 data
= (uint8_t *)data
+ offset
;
898 size_t ifwi_size
= buffer_size(buff
) - offset
;
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");
905 /* Parse S-BPDT, if any. */
906 parse_sbpdt(data
, ifwi_size
);
909 * Store end offset of IFWI. Required for copying any trailing non-IFWI
911 * ASSUMPTION: IFWI image always ends on a 4K boundary.
913 ifwi_image
.input_ifwi_end_offset
= ALIGN_UP(end_offset
, 4 * KiB
);
914 DEBUG("Parsing done.\n");
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.
925 static void __bpdt_reset(struct buffer
*b
, size_t count
, size_t size
)
927 size_t bpdt_size
= BPDT_HEADER_SIZE
+ count
* BPDT_ENTRY_SIZE
;
928 assert(size
>= bpdt_size
);
931 * If buffer does not have the required size, allocate a fresh buffer.
933 if (buffer_size(b
) != size
) {
935 alloc_buffer(&temp
, size
, b
->name
);
936 memcpy(buffer_get(&temp
), buffer_get(b
), buffer_size(b
));
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
;
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
);
950 bpdt
->h
.descriptor_count
= count
;
953 static void bpdt_reset(void)
956 size_t bpdt_count
= 0, sbpdt_count
= 0, dummy_bpdt_count
= 0;
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
) {
968 if (subparts
[i
].attr
& NON_CRITICAL_SUBPART
)
974 DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count
,
975 dummy_bpdt_count
, sbpdt_count
);
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
);
982 /* Update S-BPDT if required. */
983 bpdt_size
= ALIGN_UP(BPDT_HEADER_SIZE
+ sbpdt_count
* BPDT_ENTRY_SIZE
,
985 __bpdt_reset(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
], sbpdt_count
,
989 /* Initialize BPDT entries in header order. */
990 static void bpdt_entries_init_header_order(void)
995 struct bpdt
*bpdt
, *sbpdt
, *curr
;
996 size_t bpdt_curr
= 0, sbpdt_curr
= 0, *count_ptr
;
998 bpdt
= buffer_get(&ifwi_image
.bpdt
);
999 sbpdt
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
1001 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1002 type
= bpdt_header_order
[i
];
1003 size
= buffer_size(&ifwi_image
.subpart_buf
[type
]);
1005 if ((size
== 0) && !(subparts
[type
].attr
&
1006 MANDATORY_BPDT_ENTRY
))
1009 if (subparts
[type
].attr
& NON_CRITICAL_SUBPART
) {
1011 count_ptr
= &sbpdt_curr
;
1014 count_ptr
= &bpdt_curr
;
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
;
1027 static void pad_buffer(struct buffer
*b
, size_t size
)
1029 size_t buff_size
= buffer_size(b
);
1031 assert(buff_size
<= size
);
1033 if (buff_size
== size
)
1037 alloc_buffer(&temp
, size
, b
->name
);
1038 uint8_t *data
= buffer_get(&temp
);
1040 memcpy(data
, buffer_get(b
), buff_size
);
1041 memset(data
+ buff_size
, 0xFF, size
- buff_size
);
1046 /* Initialize offsets of entries using pack order. */
1047 static void bpdt_entries_init_pack_order(void)
1050 struct bpdt_entry
*curr
;
1051 size_t curr_offset
, curr_end
;
1053 curr_offset
= MAX(BPDT_MIN_SIZE
, buffer_size(&ifwi_image
.bpdt
));
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
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
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.
1072 /* #1 Sub-partitions that lie within same 4K as BPDT. */
1073 struct buffer
*last_bpdt_buff
= &ifwi_image
.bpdt
;
1075 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1076 type
= bpdt_pack_order
[i
];
1077 curr
= find_entry_by_type(type
);
1079 if ((curr
== NULL
) || (curr
->size
== 0))
1082 if (!(subparts
[type
].attr
& LIES_WITHIN_BPDT_4K
))
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
]));
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
;
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
);
1105 if ((curr
== NULL
) || (curr
->size
== 0))
1108 if (subparts
[type
].attr
& LIES_WITHIN_BPDT_4K
)
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
;
1116 pad_buffer(&ifwi_image
.subpart_buf
[type
], curr
->size
);
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
]));
1126 * Update size of S-BPDT to include size of all non-critical
1129 * Assumption: S-BPDT always lies at the end of IFWI image.
1131 curr
= find_entry_by_type(S_BPDT_TYPE
);
1134 assert(curr_offset
== ALIGN_UP(curr_offset
, 4 * KiB
));
1135 curr
->size
= curr_offset
- curr
->offset
;
1138 /* Convert all members of BPDT to little-endian format. */
1139 static void bpdt_fixup_write_buffer(struct buffer
*buf
)
1141 struct bpdt
*s
= buffer_get(buf
);
1143 struct bpdt_header
*h
= &s
->h
;
1144 struct bpdt_entry
*e
= &s
->e
[0];
1146 size_t count
= h
->descriptor_count
;
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
));
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
));
1169 /* Write BPDT to output buffer after fixup. */
1170 static void bpdt_write(struct buffer
*dst
, size_t offset
, struct buffer
*src
)
1172 bpdt_fixup_write_buffer(src
);
1173 memcpy(buffer_get(dst
) + offset
, buffer_get(src
), buffer_size(src
));
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.
1183 * While performing the above steps, make sure that any empty holes are filled
1186 static void ifwi_write(const char *image_name
)
1188 struct bpdt_entry
*s
= find_entry_by_type(S_BPDT_TYPE
);
1191 size_t ifwi_start
, ifwi_end
, file_end
;
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
);
1200 alloc_buffer(&b
, file_end
, "Final-IFWI");
1202 uint8_t *input_data
= buffer_get(&ifwi_image
.input_buff
);
1203 uint8_t *output_data
= buffer_get(&b
);
1205 DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start
,
1206 ifwi_end
, file_end
);
1208 /* Copy non-IFWI prefix, if any. */
1209 memcpy(output_data
, input_data
, ifwi_start
);
1211 DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start
);
1214 buffer_splice(&ifwi
, &b
, ifwi_start
, ifwi_end
- ifwi_start
);
1215 uint8_t *ifwi_data
= buffer_get(&ifwi
);
1217 /* Copy sub-partitions using pack_order. */
1218 struct bpdt_entry
*curr
;
1219 struct buffer
*subpart_buf
;
1221 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1222 type
= bpdt_pack_order
[i
];
1224 if (type
== S_BPDT_TYPE
)
1227 curr
= find_entry_by_type(type
);
1229 if ((curr
== NULL
) || (curr
->size
== 0))
1232 subpart_buf
= &ifwi_image
.subpart_buf
[type
];
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
));
1238 assert((curr
->offset
+ buffer_size(subpart_buf
)) <=
1239 buffer_size(&ifwi
));
1241 memcpy(ifwi_data
+ curr
->offset
, buffer_get(subpart_buf
),
1242 buffer_size(subpart_buf
));
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
);
1255 * Convert BPDT to little-endian format and write it to output buffer.
1256 * S-BPDT is written first and then BPDT.
1258 bpdt_write(&ifwi
, s
->offset
, &ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
1259 bpdt_write(&ifwi
, 0, &ifwi_image
.bpdt
);
1261 if (buffer_write_file(&b
, image_name
)) {
1262 ERROR("File write error\n");
1267 printf("Image written successfully to %s.\n", image_name
);
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.
1275 static void ifwi_repack(void)
1278 bpdt_entries_init_header_order();
1279 bpdt_entries_init_pack_order();
1281 struct bpdt
*b
= buffer_get(&ifwi_image
.bpdt
);
1282 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "BPDT");
1284 b
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
1285 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "S-BPDT");
1287 DEBUG("Repack done.. writing image.\n");
1288 ifwi_write(param
.image_name
);
1291 static void init_subpart_dir_header(struct subpart_dir_header
*hdr
,
1292 size_t count
, const char *name
)
1294 memset(hdr
, 0, sizeof(*hdr
));
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
));
1304 static size_t init_subpart_dir_entry(struct subpart_dir_entry
*e
,
1305 struct buffer
*b
, size_t offset
)
1307 memset(e
, 0, sizeof(*e
));
1309 assert(strlen(b
->name
) <= sizeof(e
->name
));
1310 strncpy((char *)e
->name
, (char *)b
->name
, sizeof(e
->name
));
1312 e
->length
= buffer_size(b
);
1314 return (offset
+ buffer_size(b
));
1317 static void init_manifest_header(struct manifest_header
*hdr
, size_t size
)
1319 memset(hdr
, 0, sizeof(*hdr
));
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;
1327 struct tm
*local_time
;
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);
1336 assert((size
% DWORD_SIZE
) == 0);
1337 hdr
->size
= size
/ DWORD_SIZE
;
1338 hdr
->id
= MANIFEST_ID_MAGIC
;
1341 static void init_signed_pkg_info_ext(struct signed_pkg_info_ext
*ext
,
1342 size_t count
, const char *name
)
1344 memset(ext
, 0, sizeof(*ext
));
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
));
1351 static void subpart_dir_fixup_write_buffer(struct buffer
*buf
)
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];
1357 size_t count
= h
->num_entries
;
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
);
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
));
1380 static void create_subpart(struct buffer
*dst
, struct buffer
*info
[],
1381 size_t count
, const char *name
)
1383 struct buffer subpart_dir_buff
;
1384 size_t size
= SUBPART_DIR_HEADER_SIZE
+ count
* SUBPART_DIR_ENTRY_SIZE
;
1386 alloc_buffer(&subpart_dir_buff
, size
, "subpart-dir");
1388 struct subpart_dir_header
*h
= buffer_get(&subpart_dir_buff
);
1389 struct subpart_dir_entry
*e
= (struct subpart_dir_entry
*)(h
+ 1);
1391 init_subpart_dir_header(h
, count
, name
);
1393 size_t curr_offset
= size
;
1396 for (i
= 0; i
< count
; i
++) {
1397 curr_offset
= init_subpart_dir_entry(&e
[i
], info
[i
],
1401 alloc_buffer(dst
, curr_offset
, name
);
1402 uint8_t *data
= buffer_get(dst
);
1404 for (i
= 0; i
< count
; i
++) {
1405 memcpy(data
+ e
[i
].offset
, buffer_get(info
[i
]),
1406 buffer_size(info
[i
]));
1409 h
->checksum
= calc_checksum(buffer_get(&subpart_dir_buff
));
1411 struct subpart_dir
*dir
= buffer_get(&subpart_dir_buff
);
1413 print_subpart_dir(dir
);
1415 subpart_dir_fixup_write_buffer(&subpart_dir_buff
);
1416 memcpy(data
, dir
, buffer_size(&subpart_dir_buff
));
1418 buffer_delete(&subpart_dir_buff
);
1421 static enum ifwi_ret
ibbp_dir_add(int type
)
1423 #define DUMMY_IBB_SIZE (4 * KiB)
1425 assert(type
== IBB_TYPE
);
1428 * Entry # 1 - IBBP.man
1429 * Contains manifest header and signed pkg info extension.
1431 struct buffer manifest
;
1432 size_t size
= MANIFEST_HDR_SIZE
+ SIGNED_PKG_INFO_EXT_SIZE
;
1433 alloc_buffer(&manifest
, size
, "IBBP.man");
1435 struct manifest_header
*man_hdr
= buffer_get(&manifest
);
1436 init_manifest_header(man_hdr
, size
);
1438 struct signed_pkg_info_ext
*ext
;
1439 ext
= (struct signed_pkg_info_ext
*)(man_hdr
+ 1);
1441 init_signed_pkg_info_ext(ext
, 0, subparts
[type
].name
);
1443 /* Entry # 2 - IBBL */
1445 if (buffer_from_file(&ibbl
, param
.file_name
))
1448 /* Entry # 3 - IBB */
1450 alloc_buffer(&ibb
, DUMMY_IBB_SIZE
, "IBB");
1451 memset(buffer_get(&ibb
), 0xFF, DUMMY_IBB_SIZE
);
1453 /* Create subpartition. */
1454 struct buffer
*info
[] = {
1455 &manifest
, &ibbl
, &ibb
,
1457 create_subpart(&ifwi_image
.subpart_buf
[type
], &info
[0],
1458 ARRAY_SIZE(info
), subparts
[type
].name
);
1460 return REPACK_REQUIRED
;
1463 static enum ifwi_ret
ifwi_raw_add(int type
)
1465 if (buffer_from_file(&ifwi_image
.subpart_buf
[type
], param
.file_name
))
1468 printf("Sub-partition %s(%d) added from file %s.\n", param
.subpart_name
,
1469 type
, param
.file_name
);
1470 return REPACK_REQUIRED
;
1473 static enum ifwi_ret
ifwi_dir_add(int type
)
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
);
1482 if (!param
.dentry_name
) {
1483 ERROR("%s: -e option required\n", __func__
);
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
,
1493 ERROR("Sub-partition dir operation failed.\n");
1498 static enum ifwi_ret
ifwi_add(void)
1500 if (!param
.file_name
) {
1501 ERROR("%s: -f option required\n", __func__
);
1505 if (!param
.subpart_name
) {
1506 ERROR("%s: -n option required\n", __func__
);
1510 int type
= find_type_by_name(param
.subpart_name
);
1514 const struct subpart_info
*curr_subpart
= &subparts
[type
];
1516 if (curr_subpart
->attr
& AUTO_GENERATED
) {
1517 ERROR("Cannot add auto-generated sub-partitions.\n");
1521 if (buffer_size(&ifwi_image
.subpart_buf
[type
])) {
1522 ERROR("Image already contains sub-partition %s(%d).\n",
1523 param
.subpart_name
, type
);
1528 return ifwi_dir_add(type
);
1530 return ifwi_raw_add(type
);
1533 static enum ifwi_ret
ifwi_delete(void)
1535 if (!param
.subpart_name
) {
1536 ERROR("%s: -n option required\n", __func__
);
1540 int type
= find_type_by_name(param
.subpart_name
);
1544 const struct subpart_info
*curr_subpart
= &subparts
[type
];
1546 if (curr_subpart
->attr
& AUTO_GENERATED
) {
1547 ERROR("Cannot delete auto-generated sub-partitions.\n");
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
;
1557 buffer_delete(&ifwi_image
.subpart_buf
[type
]);
1558 printf("Sub-Partition %s(%d) deleted.\n", subparts
[type
].name
, type
);
1559 return REPACK_REQUIRED
;
1562 static enum ifwi_ret
ifwi_dir_extract(int type
)
1564 if (!(subparts
[type
].attr
& CONTAINS_DIR
)) {
1565 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1566 subparts
[type
].name
, type
);
1570 if (!param
.dentry_name
) {
1571 ERROR("%s: -e option required.\n", __func__
);
1575 struct buffer subpart_dir_buff
;
1576 parse_subpart_dir(&subpart_dir_buff
, &ifwi_image
.subpart_buf
[type
],
1577 subparts
[type
].name
);
1580 struct subpart_dir
*s
= buffer_get(&subpart_dir_buff
);
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
)))
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
);
1596 DEBUG("Splicing buffer at 0x%x size 0x%x\n", s
->e
[i
].offset
,
1598 buffer_splice(&dst
, &ifwi_image
.subpart_buf
[type
], s
->e
[i
].offset
,
1601 if (buffer_write_file(&dst
, param
.file_name
))
1604 printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1605 param
.subpart_name
, type
, param
.dentry_name
, param
.file_name
);
1607 return NO_ACTION_REQUIRED
;
1610 static enum ifwi_ret
ifwi_raw_extract(int type
)
1612 if (buffer_write_file(&ifwi_image
.subpart_buf
[type
], param
.file_name
))
1615 printf("Sub-Partition %s(%d) stored in %s.\n", param
.subpart_name
, type
,
1618 return NO_ACTION_REQUIRED
;
1621 static enum ifwi_ret
ifwi_extract(void)
1623 if (!param
.file_name
) {
1624 ERROR("%s: -f option required\n", __func__
);
1628 if (!param
.subpart_name
) {
1629 ERROR("%s: -n option required\n", __func__
);
1633 int type
= find_type_by_name(param
.subpart_name
);
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
;
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
);
1649 INFO("Extracting sub-partition %s(%d).\n", param
.subpart_name
, type
);
1651 return ifwi_dir_extract(type
);
1653 return ifwi_raw_extract(type
);
1656 static enum ifwi_ret
ifwi_print(void)
1660 struct bpdt
*b
= buffer_get(&ifwi_image
.bpdt
);
1662 bpdt_print_header(&b
->h
, "BPDT");
1663 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "BPDT");
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");
1669 if (param
.dir_ops
== 0) {
1671 return NO_ACTION_REQUIRED
;
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))
1681 parse_subpart_dir(&subpart_dir_buf
, &ifwi_image
.subpart_buf
[i
],
1683 buffer_delete(&subpart_dir_buf
);
1688 return NO_ACTION_REQUIRED
;
1691 static enum ifwi_ret
ifwi_raw_replace(int type
)
1693 buffer_delete(&ifwi_image
.subpart_buf
[type
]);
1694 return ifwi_raw_add(type
);
1697 static enum ifwi_ret
ifwi_dir_replace(int type
)
1699 if (!(subparts
[type
].attr
& CONTAINS_DIR
)) {
1700 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1701 subparts
[type
].name
, type
);
1705 if (!param
.dentry_name
) {
1706 ERROR("%s: -e option required.\n", __func__
);
1710 struct buffer subpart_dir_buf
;
1711 parse_subpart_dir(&subpart_dir_buf
, &ifwi_image
.subpart_buf
[type
],
1712 subparts
[type
].name
);
1715 struct subpart_dir
*s
= buffer_get(&subpart_dir_buf
);
1717 for (i
= 0; i
< s
->h
.num_entries
; i
++) {
1718 if (!strcmp((char *)s
->e
[i
].name
, param
.dentry_name
))
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
);
1729 if (buffer_from_file(&b
, param
.file_name
)) {
1730 ERROR("Failed to read %s\n", param
.file_name
);
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
;
1740 alloc_buffer(&dst
, dst_size
, ifwi_image
.subpart_buf
[type
].name
);
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;
1746 /* Copy data before the sub-partition entry. */
1747 memcpy(dst_data
+ curr_offset
, src_data
, subpart_start
);
1748 curr_offset
+= subpart_start
;
1750 /* Copy sub-partition entry. */
1751 memcpy(dst_data
+ curr_offset
, buffer_get(&b
), buffer_size(&b
));
1752 curr_offset
+= buffer_size(&b
);
1754 /* Copy remaining data. */
1755 memcpy(dst_data
+ curr_offset
, src_data
+ subpart_end
,
1756 buffer_size(&ifwi_image
.subpart_buf
[type
]) - subpart_end
);
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
;
1763 /* Update length of entry in the subpartition. */
1764 s
->e
[i
].length
= buffer_size(&b
);
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
;
1773 /* Re-calculate checksum. */
1774 s
->h
.checksum
= calc_checksum(s
);
1776 /* Convert members to litte-endian. */
1777 subpart_dir_fixup_write_buffer(&subpart_dir_buf
);
1779 memcpy(dst_data
, buffer_get(&subpart_dir_buf
),
1780 buffer_size(&subpart_dir_buf
));
1782 buffer_delete(&subpart_dir_buf
);
1784 printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
1785 param
.subpart_name
, type
, param
.dentry_name
, param
.file_name
);
1787 return REPACK_REQUIRED
;
1790 static enum ifwi_ret
ifwi_replace(void)
1792 if (!param
.file_name
) {
1793 ERROR("%s: -f option required\n", __func__
);
1797 if (!param
.subpart_name
) {
1798 ERROR("%s: -n option required\n", __func__
);
1802 int type
= find_type_by_name(param
.subpart_name
);
1806 const struct subpart_info
*curr_subpart
= &subparts
[type
];
1808 if (curr_subpart
->attr
& AUTO_GENERATED
) {
1809 ERROR("Cannot replace auto-generated sub-partitions.\n");
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
);
1820 return ifwi_dir_replace(type
);
1822 return ifwi_raw_replace(type
);
1825 static enum ifwi_ret
ifwi_create(void)
1828 * Create peels off any non-IFWI content present in the input buffer and
1829 * creates output file with only the IFWI present.
1832 if (!param
.file_name
) {
1833 ERROR("%s: -f option required\n", __func__
);
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
);
1846 * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
1848 ifwi_image
.input_ifwi_end_offset
-= ifwi_image
.input_ifwi_start_offset
;
1849 ifwi_image
.input_ifwi_start_offset
= 0;
1851 param
.image_name
= param
.file_name
;
1853 return REPACK_REQUIRED
;
1858 const char *optstring
;
1859 enum ifwi_ret (*function
)(void);
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
},
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'},
1882 static void usage(const char *name
)
1884 printf("ifwitool: Utility for IFWI manipulation\n\n"
1887 " %s FILE COMMAND [PARAMETERS]\n\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"
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",
1906 printf("\nNAME should be one of:\n");
1908 for (i
= 0; i
< MAX_SUBPARTS
; i
++)
1909 printf("%s(%s)\n", subparts
[i
].name
, subparts
[i
].readable_name
);
1913 int main(int argc
, char **argv
)
1920 param
.image_name
= argv
[1];
1921 param
.logical_boot_partition
= LBP1
;
1922 char *cmd
= argv
[2];
1927 for (i
= 0; i
< ARRAY_SIZE(commands
); i
++) {
1928 if (strcmp(cmd
, commands
[i
].name
) != 0)
1936 c
= getopt_long(argc
, argv
, commands
[i
].optstring
,
1937 long_options
, &option_index
);
1942 /* Filter out illegal long options. */
1943 if (strchr(commands
[i
].optstring
, c
) == NULL
) {
1944 ERROR("%s: invalid option -- '%c'\n", argv
[0],
1951 param
.subpart_name
= optarg
;
1954 param
.logical_boot_partition
= LBP2
;
1957 param
.file_name
= optarg
;
1963 param
.dentry_name
= optarg
;
1978 ERROR("%s: ifwi parsing failed\n", argv
[0]);
1982 enum ifwi_ret ret
= commands
[i
].function();
1984 if (ret
== COMMAND_ERR
) {
1985 ERROR("%s: failed execution\n", argv
[0]);
1989 if (ret
== REPACK_REQUIRED
)
1995 ERROR("%s: invalid command\n", argv
[0]);