1 // SPDX-License-Identifier: GPL-2.0
3 * ifwitool, CLI utility for Integrated Firmware Image (IFWI) manipulation
5 * This is taken from the Coreboot project
11 #include "imagetool.h"
12 #include "os_support.h"
15 #define __packed __attribute__((packed))
20 * min()/max()/clamp() macros that also do
21 * strict type-checking.. See the
22 * "unnecessary" pointer comparison.
24 #define min(x, y) ({ \
25 typeof(x) _min1 = (x); \
26 typeof(y) _min2 = (y); \
27 (void)&_min1 == &_min2); \
28 _min1 < _min2 ? _min1 : _min2; })
30 #define max(x, y) ({ \
31 typeof(x) _max1 = (x); \
32 typeof(y) _max2 = (y); \
33 (void)(&_max1 == &_max2); \
34 _max1 > _max2 ? _max1 : _max2; })
36 static int verbose
= 1;
38 /* Buffer and file I/O */
46 #define ERROR(...) { fprintf(stderr, "E: " __VA_ARGS__); }
47 #define INFO(...) { if (verbose > 0) fprintf(stderr, "INFO: " __VA_ARGS__); }
48 #define DEBUG(...) { if (verbose > 1) fprintf(stderr, "DEBUG: " __VA_ARGS__); }
51 * BPDT is Boot Partition Descriptor Table. It is located at the start of a
52 * logical boot partition(LBP). It stores information about the critical
53 * sub-partitions present within the LBP.
55 * S-BPDT is Secondary Boot Partition Descriptor Table. It is located after the
56 * critical sub-partitions and contains information about the non-critical
57 * sub-partitions present within the LBP.
59 * Both tables are identified by BPDT_SIGNATURE stored at the start of the
62 #define BPDT_SIGNATURE (0x000055AA)
64 /* Parameters passed in by caller */
66 const char *file_name
;
67 const char *subpart_name
;
68 const char *image_name
;
70 const char *dentry_name
;
75 * This is used to identify start of BPDT. It should always be
79 /* Count of BPDT entries present */
80 uint16_t descriptor_count
;
81 /* Version - Currently supported = 1 */
82 uint16_t bpdt_version
;
83 /* Unused - Should be 0 */
84 uint32_t xor_redundant_block
;
85 /* Version of IFWI build */
86 uint32_t ifwi_version
;
87 /* Version of FIT tool used to create IFWI */
88 uint64_t fit_tool_version
;
90 #define BPDT_HEADER_SIZE (sizeof(struct bpdt_header))
93 /* Type of sub-partition */
95 /* Attributes of sub-partition */
97 /* Offset of sub-partition from beginning of LBP */
99 /* Size in bytes of sub-partition */
102 #define BPDT_ENTRY_SIZE (sizeof(struct bpdt_entry))
105 struct bpdt_header h
;
106 /* In practice, this could be an array of 0 to n entries */
107 struct bpdt_entry e
[0];
110 static inline size_t get_bpdt_size(struct bpdt_header
*h
)
112 return (sizeof(*h
) + BPDT_ENTRY_SIZE
* h
->descriptor_count
);
115 /* Minimum size in bytes allocated to BPDT in IFWI */
116 #define BPDT_MIN_SIZE ((size_t)512)
118 /* Header to define directory header for sub-partition */
119 struct subpart_dir_header
{
120 /* Should be SUBPART_DIR_MARKER */
122 /* Number of directory entries in the sub-partition */
123 uint32_t num_entries
;
124 /* Currenty supported - 1 */
125 uint8_t header_version
;
126 /* Currenty supported - 1 */
127 uint8_t entry_version
;
128 /* Length of directory header in bytes */
129 uint8_t header_length
;
131 * 2s complement of 8-bit sum from first byte of header to last byte of
132 * last directory entry.
135 /* ASCII short name of sub-partition */
138 #define SUBPART_DIR_HEADER_SIZE \
139 (sizeof(struct subpart_dir_header))
140 #define SUBPART_DIR_MARKER 0x44504324
141 #define SUBPART_DIR_HEADER_VERSION_SUPPORTED 1
142 #define SUBPART_DIR_ENTRY_VERSION_SUPPORTED 1
144 /* Structure for each directory entry for sub-partition */
145 struct subpart_dir_entry
{
146 /* Name of directory entry - Not guaranteed to be NULL-terminated */
148 /* Offset of entry from beginning of sub-partition */
150 /* Length in bytes of sub-directory entry */
155 #define SUBPART_DIR_ENTRY_SIZE \
156 (sizeof(struct subpart_dir_entry))
159 struct subpart_dir_header h
;
160 /* In practice, this could be an array of 0 to n entries */
161 struct subpart_dir_entry e
[0];
164 static inline size_t subpart_dir_size(struct subpart_dir_header
*h
)
166 return (sizeof(*h
) + SUBPART_DIR_ENTRY_SIZE
* h
->num_entries
);
169 struct manifest_header
{
170 uint32_t header_type
;
171 uint32_t header_length
;
172 uint32_t header_version
;
183 uint32_t modulus_size
;
184 uint32_t exponent_size
;
185 uint8_t public_key
[256];
187 uint8_t signature
[256];
191 #define MANIFEST_HDR_SIZE (sizeof(struct manifest_header))
192 #define MANIFEST_ID_MAGIC (0x324e4d24)
199 uint32_t metadata_size
;
200 uint8_t metadata_hash
[32];
203 #define MODULE_SIZE (sizeof(struct module))
205 struct signed_pkg_info_ext
{
215 #define SIGNED_PKG_INFO_EXT_TYPE 0x15
216 #define SIGNED_PKG_INFO_EXT_SIZE \
217 (sizeof(struct signed_pkg_info_ext))
220 * Attributes for various IFWI sub-partitions.
221 * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
223 * NON_CRITICAL_SUBPART = Sub-Partition entry should be present in S-BPDT.
224 * CONTAINS_DIR = Sub-Partition contains directory.
225 * AUTO_GENERATED = Sub-Partition is generated by the tool.
226 * MANDATORY_BPDT_ENTRY = Even if sub-partition is deleted, BPDT should contain
227 * an entry for it with size 0 and offset 0.
229 enum subpart_attributes
{
230 LIES_WITHIN_BPDT_4K
= (1 << 0),
231 NON_CRITICAL_SUBPART
= (1 << 1),
232 CONTAINS_DIR
= (1 << 2),
233 AUTO_GENERATED
= (1 << 3),
234 MANDATORY_BPDT_ENTRY
= (1 << 4),
237 /* Type value for various IFWI sub-partitions */
238 enum bpdt_entry_type
{
249 IFP_OVERRIDE_TYPE
= 10,
250 DEBUG_TOKENS_TYPE
= 11,
255 NVM_CONFIG_TYPE
= 16,
257 UFS_RATE_B_TYPE
= 18,
262 * There are two order requirements for an IFWI image:
263 * 1. Order in which the sub-partitions lie within the BPDT entries.
264 * 2. Order in which the sub-partitions lie within the image.
266 * header_order defines #1 i.e. the order in which the sub-partitions should
267 * appear in the BPDT entries. pack_order defines #2 i.e. the order in which
268 * sub-partitions appear in the IFWI image. pack_order controls the offset and
269 * thus sub-partitions would have increasing offsets as we loop over pack_order.
271 const enum bpdt_entry_type bpdt_header_order
[MAX_SUBPARTS
] = {
272 /* Order of the following entries is mandatory */
279 /* Order of the following entries is recommended */
295 const enum bpdt_entry_type bpdt_pack_order
[MAX_SUBPARTS
] = {
296 /* Order of the following entries is mandatory */
303 /* Order of the following entries is recommended */
319 /* Utility functions */
322 NO_ACTION_REQUIRED
= 0,
327 enum ifwi_ret (*dir_add
)(int type
);
330 static enum ifwi_ret
ibbp_dir_add(int type
);
332 const struct subpart_info
{
334 const char *readable_name
;
336 struct dir_ops dir_ops
;
337 } subparts
[MAX_SUBPARTS
] = {
339 [SMIP_TYPE
] = {"SMIP", "SMIP", CONTAINS_DIR
, {NULL
} },
341 [CSE_RBE_TYPE
] = {"RBEP", "CSE_RBE", CONTAINS_DIR
|
342 MANDATORY_BPDT_ENTRY
, {NULL
} },
344 [CSE_BUP_TYPE
] = {"FTPR", "CSE_BUP", CONTAINS_DIR
|
345 MANDATORY_BPDT_ENTRY
, {NULL
} },
347 [UCODE_TYPE
] = {"UCOD", "Microcode", CONTAINS_DIR
, {NULL
} },
349 [IBB_TYPE
] = {"IBBP", "Bootblock", CONTAINS_DIR
, {ibbp_dir_add
} },
351 [S_BPDT_TYPE
] = {"S_BPDT", "S-BPDT", AUTO_GENERATED
|
352 MANDATORY_BPDT_ENTRY
, {NULL
} },
354 [OBB_TYPE
] = {"OBBP", "OEM boot block", CONTAINS_DIR
|
355 NON_CRITICAL_SUBPART
, {NULL
} },
357 [CSE_MAIN_TYPE
] = {"NFTP", "CSE_MAIN", CONTAINS_DIR
|
358 NON_CRITICAL_SUBPART
, {NULL
} },
360 [ISH_TYPE
] = {"ISHP", "ISH", NON_CRITICAL_SUBPART
, {NULL
} },
362 [CSE_IDLM_TYPE
] = {"DLMP", "CSE_IDLM", CONTAINS_DIR
|
363 MANDATORY_BPDT_ENTRY
, {NULL
} },
365 [IFP_OVERRIDE_TYPE
] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
366 LIES_WITHIN_BPDT_4K
| MANDATORY_BPDT_ENTRY
,
369 [DEBUG_TOKENS_TYPE
] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL
} },
370 /* UFS Phy Configuration */
371 [UFS_PHY_TYPE
] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K
|
372 MANDATORY_BPDT_ENTRY
, {NULL
} },
374 [UFS_GPP_TYPE
] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K
|
375 MANDATORY_BPDT_ENTRY
, {NULL
} },
377 [PMC_TYPE
] = {"PMCP", "PMC firmware", CONTAINS_DIR
, {NULL
} },
379 [IUNIT_TYPE
] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART
, {NULL
} },
381 [NVM_CONFIG_TYPE
] = {"NVM_CONFIG", "NVM Config", 0, {NULL
} },
383 [UEP_TYPE
] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K
| MANDATORY_BPDT_ENTRY
,
385 /* UFS Rate B Config */
386 [UFS_RATE_B_TYPE
] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL
} },
390 /* Data read from input file */
391 struct buffer input_buff
;
393 /* BPDT header and entries */
395 size_t input_ifwi_start_offset
;
396 size_t input_ifwi_end_offset
;
398 /* Subpartition content */
399 struct buffer subpart_buf
[MAX_SUBPARTS
];
402 /* Buffer and file I/O */
403 static off_t
get_file_size(FILE *f
)
407 fseek(f
, 0, SEEK_END
);
409 fseek(f
, 0, SEEK_SET
);
413 static inline void *buffer_get(const struct buffer
*b
)
418 static inline size_t buffer_size(const struct buffer
*b
)
423 static inline size_t buffer_offset(const struct buffer
*b
)
429 * Shrink a buffer toward the beginning of its previous space.
430 * Afterward, buffer_delete() remains the means of cleaning it up
432 static inline void buffer_set_size(struct buffer
*b
, size_t size
)
437 /* Splice a buffer into another buffer. Note that it's up to the caller to
438 * bounds check the offset and size. The resulting buffer is backed by the same
439 * storage as the original, so although it is valid to buffer_delete() either
440 * one of them, doing so releases both simultaneously
442 static void buffer_splice(struct buffer
*dest
, const struct buffer
*src
,
443 size_t offset
, size_t size
)
445 dest
->name
= src
->name
;
446 dest
->data
= src
->data
+ offset
;
447 dest
->offset
= src
->offset
+ offset
;
452 * Shrink a buffer toward the end of its previous space.
453 * Afterward, buffer_delete() remains the means of cleaning it up
455 static inline void buffer_seek(struct buffer
*b
, size_t size
)
462 /* Returns the start of the underlying buffer, with the offset undone */
463 static inline void *buffer_get_original_backing(const struct buffer
*b
)
467 return buffer_get(b
) - buffer_offset(b
);
470 int buffer_create(struct buffer
*buffer
, size_t size
, const char *name
)
472 buffer
->name
= strdup(name
);
475 buffer
->data
= (char *)malloc(buffer
->size
);
477 fprintf(stderr
, "%s: Insufficient memory (0x%zx).\n", __func__
,
481 return !buffer
->data
;
484 int buffer_write_file(struct buffer
*buffer
, const char *filename
)
486 FILE *fp
= fopen(filename
, "wb");
492 assert(buffer
&& buffer
->data
);
493 if (fwrite(buffer
->data
, 1, buffer
->size
, fp
) != buffer
->size
) {
494 fprintf(stderr
, "incomplete write: %s\n", filename
);
502 void buffer_delete(struct buffer
*buffer
)
510 free(buffer_get_original_backing(buffer
));
517 int buffer_from_file(struct buffer
*buffer
, const char *filename
)
519 FILE *fp
= fopen(filename
, "rb");
526 off_t file_size
= get_file_size(fp
);
529 fprintf(stderr
, "could not determine size of %s\n", filename
);
533 buffer
->size
= file_size
;
534 buffer
->name
= strdup(filename
);
535 buffer
->data
= (char *)malloc(buffer
->size
);
536 assert(buffer
->data
);
537 if (fread(buffer
->data
, 1, buffer
->size
, fp
) != buffer
->size
) {
538 fprintf(stderr
, "incomplete read: %s\n", filename
);
540 buffer_delete(buffer
);
547 static void alloc_buffer(struct buffer
*b
, size_t s
, const char *n
)
549 if (buffer_create(b
, s
, n
) == 0)
552 ERROR("Buffer allocation failure for %s (size = %zx).\n", n
, s
);
556 /* Little-Endian functions */
557 static inline uint8_t read_ble8(const void *src
)
559 const uint8_t *s
= src
;
563 static inline uint8_t read_at_ble8(const void *src
, size_t offset
)
565 const uint8_t *s
= src
;
571 static inline void write_ble8(void *dest
, uint8_t val
)
573 *(uint8_t *)dest
= val
;
576 static inline void write_at_ble8(void *dest
, uint8_t val
, size_t offset
)
584 static inline uint8_t read_at_le8(const void *src
, size_t offset
)
586 return read_at_ble8(src
, offset
);
589 static inline void write_le8(void *dest
, uint8_t val
)
591 write_ble8(dest
, val
);
594 static inline void write_at_le8(void *dest
, uint8_t val
, size_t offset
)
596 write_at_ble8(dest
, val
, offset
);
599 static inline uint16_t read_le16(const void *src
)
601 const uint8_t *s
= src
;
603 return (((uint16_t)s
[1]) << 8) | (((uint16_t)s
[0]) << 0);
606 static inline uint16_t read_at_le16(const void *src
, size_t offset
)
608 const uint8_t *s
= src
;
614 static inline void write_le16(void *dest
, uint16_t val
)
616 write_le8(dest
, val
>> 0);
617 write_at_le8(dest
, val
>> 8, sizeof(uint8_t));
620 static inline void write_at_le16(void *dest
, uint16_t val
, size_t offset
)
628 static inline uint32_t read_le32(const void *src
)
630 const uint8_t *s
= src
;
632 return (((uint32_t)s
[3]) << 24) | (((uint32_t)s
[2]) << 16) |
633 (((uint32_t)s
[1]) << 8) | (((uint32_t)s
[0]) << 0);
636 static inline uint32_t read_at_le32(const void *src
, size_t offset
)
638 const uint8_t *s
= src
;
644 static inline void write_le32(void *dest
, uint32_t val
)
646 write_le16(dest
, val
>> 0);
647 write_at_le16(dest
, val
>> 16, sizeof(uint16_t));
650 static inline void write_at_le32(void *dest
, uint32_t val
, size_t offset
)
658 static inline uint64_t read_le64(const void *src
)
662 val
= read_at_le32(src
, sizeof(uint32_t));
664 val
|= read_le32(src
);
668 static inline uint64_t read_at_le64(const void *src
, size_t offset
)
670 const uint8_t *s
= src
;
676 static inline void write_le64(void *dest
, uint64_t val
)
678 write_le32(dest
, val
>> 0);
679 write_at_le32(dest
, val
>> 32, sizeof(uint32_t));
682 static inline void write_at_le64(void *dest
, uint64_t val
, size_t offset
)
691 * Read header/entry members in little-endian format.
692 * Returns the offset upto which the read was performed.
694 static size_t read_member(void *src
, size_t offset
, size_t size_bytes
,
697 switch (size_bytes
) {
699 *(uint8_t *)dst
= read_at_le8(src
, offset
);
702 *(uint16_t *)dst
= read_at_le16(src
, offset
);
705 *(uint32_t *)dst
= read_at_le32(src
, offset
);
708 *(uint64_t *)dst
= read_at_le64(src
, offset
);
711 ERROR("Read size not supported %zd\n", size_bytes
);
715 return (offset
+ size_bytes
);
719 * Convert to little endian format.
720 * Returns the offset upto which the fixup was performed.
722 static size_t fix_member(void *data
, size_t offset
, size_t size_bytes
)
724 void *src
= (uint8_t *)data
+ offset
;
726 switch (size_bytes
) {
728 write_at_le8(data
, *(uint8_t *)src
, offset
);
731 write_at_le16(data
, *(uint16_t *)src
, offset
);
734 write_at_le32(data
, *(uint32_t *)src
, offset
);
737 write_at_le64(data
, *(uint64_t *)src
, offset
);
740 ERROR("Write size not supported %zd\n", size_bytes
);
743 return (offset
+ size_bytes
);
746 static void print_subpart_dir(struct subpart_dir
*s
)
753 printf("%-25s 0x%-23.8x\n", "Marker", s
->h
.marker
);
754 printf("%-25s %-25d\n", "Num entries", s
->h
.num_entries
);
755 printf("%-25s %-25d\n", "Header Version", s
->h
.header_version
);
756 printf("%-25s %-25d\n", "Entry Version", s
->h
.entry_version
);
757 printf("%-25s 0x%-23x\n", "Header Length", s
->h
.header_length
);
758 printf("%-25s 0x%-23x\n", "Checksum", s
->h
.checksum
);
759 printf("%-25s ", "Name");
760 for (i
= 0; i
< sizeof(s
->h
.name
); i
++)
761 printf("%c", s
->h
.name
[i
]);
765 printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
768 printf("=========================================================================================================================\n");
770 for (i
= 0; i
< s
->h
.num_entries
; i
++) {
771 printf("%-25zd%-25.12s0x%-23x0x%-23x0x%-23x\n", i
+ 1,
772 s
->e
[i
].name
, s
->e
[i
].offset
, s
->e
[i
].length
,
776 printf("=========================================================================================================================\n");
779 static void bpdt_print_header(struct bpdt_header
*h
, const char *name
)
784 printf("%-25s %-25s\n", "Header", name
);
785 printf("%-25s 0x%-23.8x\n", "Signature", h
->signature
);
786 printf("%-25s %-25d\n", "Descriptor count", h
->descriptor_count
);
787 printf("%-25s %-25d\n", "BPDT Version", h
->bpdt_version
);
788 printf("%-25s 0x%-23x\n", "XOR checksum", h
->xor_redundant_block
);
789 printf("%-25s 0x%-23x\n", "IFWI Version", h
->ifwi_version
);
790 printf("%-25s 0x%-23llx\n", "FIT Tool Version",
791 (long long)h
->fit_tool_version
);
794 static void bpdt_print_entries(struct bpdt_entry
*e
, size_t count
,
802 printf("%s entries\n", name
);
804 printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
805 "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
808 printf("=========================================================================================================================================================================================================\n");
810 for (i
= 0; i
< count
; i
++) {
811 printf("%-25zd%-25s%-25s%-25d0x%-23.08x0x%-23x0x%-23x0x%-23zx\n",
812 i
+ 1, subparts
[e
[i
].type
].name
,
813 subparts
[e
[i
].type
].readable_name
, e
[i
].type
, e
[i
].flags
,
814 e
[i
].offset
, e
[i
].size
,
815 e
[i
].offset
+ ifwi_image
.input_ifwi_start_offset
);
818 printf("=========================================================================================================================================================================================================\n");
821 static void bpdt_validate_header(struct bpdt_header
*h
, const char *name
)
823 assert(h
->signature
== BPDT_SIGNATURE
);
825 if (h
->bpdt_version
!= 1) {
826 ERROR("Invalid header : %s\n", name
);
830 DEBUG("Validated header : %s\n", name
);
833 static void bpdt_read_header(void *data
, struct bpdt_header
*h
,
838 offset
= read_member(data
, offset
, sizeof(h
->signature
), &h
->signature
);
839 offset
= read_member(data
, offset
, sizeof(h
->descriptor_count
),
840 &h
->descriptor_count
);
841 offset
= read_member(data
, offset
, sizeof(h
->bpdt_version
),
843 offset
= read_member(data
, offset
, sizeof(h
->xor_redundant_block
),
844 &h
->xor_redundant_block
);
845 offset
= read_member(data
, offset
, sizeof(h
->ifwi_version
),
847 read_member(data
, offset
, sizeof(h
->fit_tool_version
),
848 &h
->fit_tool_version
);
850 bpdt_validate_header(h
, name
);
851 bpdt_print_header(h
, name
);
854 static void bpdt_read_entries(void *data
, struct bpdt
*bpdt
, const char *name
)
856 size_t i
, offset
= 0;
857 struct bpdt_entry
*e
= &bpdt
->e
[0];
858 size_t count
= bpdt
->h
.descriptor_count
;
860 for (i
= 0; i
< count
; i
++) {
861 offset
= read_member(data
, offset
, sizeof(e
[i
].type
),
863 offset
= read_member(data
, offset
, sizeof(e
[i
].flags
),
865 offset
= read_member(data
, offset
, sizeof(e
[i
].offset
),
867 offset
= read_member(data
, offset
, sizeof(e
[i
].size
),
871 bpdt_print_entries(e
, count
, name
);
875 * Given type of sub-partition, identify BPDT entry for it.
876 * Sub-Partition could lie either within BPDT or S-BPDT.
878 static struct bpdt_entry
*__find_entry_by_type(struct bpdt_entry
*e
,
879 size_t count
, int type
)
883 for (i
= 0; i
< count
; i
++) {
884 if (e
[i
].type
== type
)
894 static struct bpdt_entry
*find_entry_by_type(int type
)
896 struct bpdt
*b
= buffer_get(&ifwi_image
.bpdt
);
901 struct bpdt_entry
*curr
= __find_entry_by_type(&b
->e
[0],
902 b
->h
.descriptor_count
,
908 b
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
912 return __find_entry_by_type(&b
->e
[0], b
->h
.descriptor_count
, type
);
916 * Find sub-partition type given its name. If the name does not exist, returns
919 static int find_type_by_name(const char *name
)
923 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
924 if ((strlen(subparts
[i
].name
) == strlen(name
)) &&
925 (!strcmp(subparts
[i
].name
, name
)))
929 if (i
== MAX_SUBPARTS
) {
930 ERROR("Invalid sub-partition name %s.\n", name
);
938 * Read the content of a sub-partition from input file and store it in
939 * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
941 * Returns the maximum offset occupied by the sub-partitions.
943 static size_t read_subpart_buf(void *data
, size_t size
, struct bpdt_entry
*e
,
948 size_t max_offset
= 0;
950 for (i
= 0; i
< count
; i
++) {
953 if (type
>= MAX_SUBPARTS
) {
954 ERROR("Invalid sub-partition type %zd.\n", type
);
958 if (buffer_size(&ifwi_image
.subpart_buf
[type
])) {
959 ERROR("Multiple sub-partitions of type %zd(%s).\n",
960 type
, subparts
[type
].name
);
964 if (e
[i
].size
== 0) {
965 INFO("Dummy sub-partition %zd(%s). Skipping.\n", type
,
966 subparts
[type
].name
);
970 assert((e
[i
].offset
+ e
[i
].size
) <= size
);
973 * Sub-partitions in IFWI image are not in the same order as
974 * in BPDT entries. BPDT entires are in header_order whereas
975 * sub-partition offsets in the image are in pack_order.
977 if ((e
[i
].offset
+ e
[i
].size
) > max_offset
)
978 max_offset
= e
[i
].offset
+ e
[i
].size
;
981 * S-BPDT sub-partition contains information about all the
982 * non-critical sub-partitions. Thus, size of S-BPDT
983 * sub-partition equals size of S-BPDT plus size of all the
984 * non-critical sub-partitions. Thus, reading whole of S-BPDT
985 * here would be redundant as the non-critical partitions are
986 * read and allocated buffers separately. Also, S-BPDT requires
987 * special handling for reading header and entries.
989 if (type
== S_BPDT_TYPE
)
992 buf
= &ifwi_image
.subpart_buf
[type
];
994 alloc_buffer(buf
, e
[i
].size
, subparts
[type
].name
);
995 memcpy(buffer_get(buf
), (uint8_t *)data
+ e
[i
].offset
,
1004 * Allocate buffer for bpdt header, entries and all sub-partition content.
1005 * Returns offset in data where BPDT ends.
1007 static size_t alloc_bpdt_buffer(void *data
, size_t size
, size_t offset
,
1008 struct buffer
*b
, const char *name
)
1010 struct bpdt_header bpdt_header
;
1012 assert((offset
+ BPDT_HEADER_SIZE
) < size
);
1013 bpdt_read_header((uint8_t *)data
+ offset
, &bpdt_header
, name
);
1015 /* Buffer to read BPDT header and entries */
1016 alloc_buffer(b
, get_bpdt_size(&bpdt_header
), name
);
1018 struct bpdt
*bpdt
= buffer_get(b
);
1020 memcpy(&bpdt
->h
, &bpdt_header
, BPDT_HEADER_SIZE
);
1023 * If no entries are present, maximum offset occupied is (offset +
1024 * BPDT_HEADER_SIZE).
1026 if (bpdt
->h
.descriptor_count
== 0)
1027 return (offset
+ BPDT_HEADER_SIZE
);
1029 /* Read all entries */
1030 assert((offset
+ get_bpdt_size(&bpdt
->h
)) < size
);
1031 bpdt_read_entries((uint8_t *)data
+ offset
+ BPDT_HEADER_SIZE
, bpdt
,
1034 /* Read all sub-partition content in subpart_buf */
1035 return read_subpart_buf(data
, size
, &bpdt
->e
[0],
1036 bpdt
->h
.descriptor_count
);
1039 static void parse_sbpdt(void *data
, size_t size
)
1041 struct bpdt_entry
*s
;
1043 s
= find_entry_by_type(S_BPDT_TYPE
);
1047 assert(size
> s
->offset
);
1049 alloc_bpdt_buffer(data
, size
, s
->offset
,
1050 &ifwi_image
.subpart_buf
[S_BPDT_TYPE
],
1054 static uint8_t calc_checksum(struct subpart_dir
*s
)
1056 size_t size
= subpart_dir_size(&s
->h
);
1057 uint8_t *data
= (uint8_t *)s
;
1058 uint8_t checksum
= 0;
1060 uint8_t old_checksum
= s
->h
.checksum
;
1064 for (i
= 0; i
< size
; i
++)
1065 checksum
+= data
[i
];
1067 s
->h
.checksum
= old_checksum
;
1073 static void validate_subpart_dir(struct subpart_dir
*s
, const char *name
,
1074 bool checksum_check
)
1076 if (s
->h
.marker
!= SUBPART_DIR_MARKER
||
1077 s
->h
.header_version
!= SUBPART_DIR_HEADER_VERSION_SUPPORTED
||
1078 s
->h
.entry_version
!= SUBPART_DIR_ENTRY_VERSION_SUPPORTED
||
1079 s
->h
.header_length
!= SUBPART_DIR_HEADER_SIZE
) {
1080 ERROR("Invalid subpart_dir for %s.\n", name
);
1084 if (!checksum_check
)
1087 uint8_t checksum
= calc_checksum(s
);
1089 if (checksum
!= s
->h
.checksum
)
1090 ERROR("Invalid checksum for %s (Expected=0x%x, Actual=0x%x).\n",
1091 name
, checksum
, s
->h
.checksum
);
1094 static void validate_subpart_dir_without_checksum(struct subpart_dir
*s
,
1097 validate_subpart_dir(s
, name
, 0);
1100 static void validate_subpart_dir_with_checksum(struct subpart_dir
*s
,
1103 validate_subpart_dir(s
, name
, 1);
1106 static void parse_subpart_dir(struct buffer
*subpart_dir_buf
,
1107 struct buffer
*input_buf
, const char *name
)
1109 struct subpart_dir_header hdr
;
1111 uint8_t *data
= buffer_get(input_buf
);
1112 size_t size
= buffer_size(input_buf
);
1114 /* Read Subpart_Dir header */
1115 assert(size
>= SUBPART_DIR_HEADER_SIZE
);
1116 offset
= read_member(data
, offset
, sizeof(hdr
.marker
), &hdr
.marker
);
1117 offset
= read_member(data
, offset
, sizeof(hdr
.num_entries
),
1119 offset
= read_member(data
, offset
, sizeof(hdr
.header_version
),
1120 &hdr
.header_version
);
1121 offset
= read_member(data
, offset
, sizeof(hdr
.entry_version
),
1122 &hdr
.entry_version
);
1123 offset
= read_member(data
, offset
, sizeof(hdr
.header_length
),
1124 &hdr
.header_length
);
1125 offset
= read_member(data
, offset
, sizeof(hdr
.checksum
), &hdr
.checksum
);
1126 memcpy(hdr
.name
, data
+ offset
, sizeof(hdr
.name
));
1127 offset
+= sizeof(hdr
.name
);
1129 validate_subpart_dir_without_checksum((struct subpart_dir
*)&hdr
, name
);
1131 assert(size
> subpart_dir_size(&hdr
));
1132 alloc_buffer(subpart_dir_buf
, subpart_dir_size(&hdr
), "Subpart Dir");
1133 memcpy(buffer_get(subpart_dir_buf
), &hdr
, SUBPART_DIR_HEADER_SIZE
);
1135 /* Read Subpart Dir entries */
1136 struct subpart_dir
*subpart_dir
= buffer_get(subpart_dir_buf
);
1137 struct subpart_dir_entry
*e
= &subpart_dir
->e
[0];
1140 for (i
= 0; i
< hdr
.num_entries
; i
++) {
1141 memcpy(e
[i
].name
, data
+ offset
, sizeof(e
[i
].name
));
1142 offset
+= sizeof(e
[i
].name
);
1143 offset
= read_member(data
, offset
, sizeof(e
[i
].offset
),
1145 offset
= read_member(data
, offset
, sizeof(e
[i
].length
),
1147 offset
= read_member(data
, offset
, sizeof(e
[i
].rsvd
),
1151 validate_subpart_dir_with_checksum(subpart_dir
, name
);
1153 print_subpart_dir(subpart_dir
);
1156 /* Parse input image file to identify different sub-partitions */
1157 static int ifwi_parse(void)
1159 struct buffer
*buff
= &ifwi_image
.input_buff
;
1160 const char *image_name
= param
.image_name
;
1162 DEBUG("Parsing IFWI image...\n");
1164 /* Read input file */
1165 if (buffer_from_file(buff
, image_name
)) {
1166 ERROR("Failed to read input file %s.\n", image_name
);
1170 INFO("Buffer %p size 0x%zx\n", buff
->data
, buff
->size
);
1172 /* Look for BPDT signature at 4K intervals */
1174 void *data
= buffer_get(buff
);
1176 while (offset
< buffer_size(buff
)) {
1177 if (read_at_le32(data
, offset
) == BPDT_SIGNATURE
)
1182 if (offset
>= buffer_size(buff
)) {
1183 ERROR("Image does not contain BPDT!!\n");
1187 ifwi_image
.input_ifwi_start_offset
= offset
;
1188 INFO("BPDT starts at offset 0x%zx.\n", offset
);
1190 data
= (uint8_t *)data
+ offset
;
1191 size_t ifwi_size
= buffer_size(buff
) - offset
;
1193 /* Read BPDT and sub-partitions */
1194 uintptr_t end_offset
;
1196 end_offset
= ifwi_image
.input_ifwi_start_offset
+
1197 alloc_bpdt_buffer(data
, ifwi_size
, 0, &ifwi_image
.bpdt
, "BPDT");
1199 /* Parse S-BPDT, if any */
1200 parse_sbpdt(data
, ifwi_size
);
1203 * Store end offset of IFWI. Required for copying any trailing non-IFWI
1204 * part of the image.
1205 * ASSUMPTION: IFWI image always ends on a 4K boundary.
1207 ifwi_image
.input_ifwi_end_offset
= ALIGN(end_offset
, 4 * KiB
);
1208 DEBUG("Parsing done.\n");
1214 * This function is used by repack to count the number of BPDT and S-BPDT
1215 * entries that are present. It frees the current buffers used by the entries
1216 * and allocates fresh buffers that can be used for repacking. Returns BPDT
1217 * entries which are empty and need to be filled in.
1219 static void __bpdt_reset(struct buffer
*b
, size_t count
, size_t size
)
1221 size_t bpdt_size
= BPDT_HEADER_SIZE
+ count
* BPDT_ENTRY_SIZE
;
1223 assert(size
>= bpdt_size
);
1226 * If buffer does not have the required size, allocate a fresh buffer.
1228 if (buffer_size(b
) != size
) {
1231 alloc_buffer(&temp
, size
, b
->name
);
1232 memcpy(buffer_get(&temp
), buffer_get(b
), buffer_size(b
));
1237 struct bpdt
*bpdt
= buffer_get(b
);
1238 uint8_t *ptr
= (uint8_t *)&bpdt
->e
[0];
1239 size_t entries_size
= BPDT_ENTRY_SIZE
* count
;
1241 /* Zero out BPDT entries */
1242 memset(ptr
, 0, entries_size
);
1243 /* Fill any pad-space with FF */
1244 memset(ptr
+ entries_size
, 0xFF, size
- bpdt_size
);
1246 bpdt
->h
.descriptor_count
= count
;
1249 static void bpdt_reset(void)
1252 size_t bpdt_count
= 0, sbpdt_count
= 0, dummy_bpdt_count
= 0;
1254 /* Count number of BPDT and S-BPDT entries */
1255 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1256 if (buffer_size(&ifwi_image
.subpart_buf
[i
]) == 0) {
1257 if (subparts
[i
].attr
& MANDATORY_BPDT_ENTRY
) {
1264 if (subparts
[i
].attr
& NON_CRITICAL_SUBPART
)
1270 DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count
,
1271 dummy_bpdt_count
, sbpdt_count
);
1273 /* Update BPDT if required */
1274 size_t bpdt_size
= max(BPDT_MIN_SIZE
,
1275 BPDT_HEADER_SIZE
+ bpdt_count
* BPDT_ENTRY_SIZE
);
1276 __bpdt_reset(&ifwi_image
.bpdt
, bpdt_count
, bpdt_size
);
1278 /* Update S-BPDT if required */
1279 bpdt_size
= ALIGN(BPDT_HEADER_SIZE
+ sbpdt_count
* BPDT_ENTRY_SIZE
,
1281 __bpdt_reset(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
], sbpdt_count
,
1285 /* Initialize BPDT entries in header order */
1286 static void bpdt_entries_init_header_order(void)
1291 struct bpdt
*bpdt
, *sbpdt
, *curr
;
1292 size_t bpdt_curr
= 0, sbpdt_curr
= 0, *count_ptr
;
1294 bpdt
= buffer_get(&ifwi_image
.bpdt
);
1295 sbpdt
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
1297 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1298 type
= bpdt_header_order
[i
];
1299 size
= buffer_size(&ifwi_image
.subpart_buf
[type
]);
1301 if (size
== 0 && !(subparts
[type
].attr
& MANDATORY_BPDT_ENTRY
))
1304 if (subparts
[type
].attr
& NON_CRITICAL_SUBPART
) {
1306 count_ptr
= &sbpdt_curr
;
1309 count_ptr
= &bpdt_curr
;
1312 assert(*count_ptr
< curr
->h
.descriptor_count
);
1313 curr
->e
[*count_ptr
].type
= type
;
1314 curr
->e
[*count_ptr
].flags
= 0;
1315 curr
->e
[*count_ptr
].offset
= 0;
1316 curr
->e
[*count_ptr
].size
= size
;
1322 static void pad_buffer(struct buffer
*b
, size_t size
)
1324 size_t buff_size
= buffer_size(b
);
1326 assert(buff_size
<= size
);
1328 if (buff_size
== size
)
1333 alloc_buffer(&temp
, size
, b
->name
);
1334 uint8_t *data
= buffer_get(&temp
);
1336 memcpy(data
, buffer_get(b
), buff_size
);
1337 memset(data
+ buff_size
, 0xFF, size
- buff_size
);
1342 /* Initialize offsets of entries using pack order */
1343 static void bpdt_entries_init_pack_order(void)
1346 struct bpdt_entry
*curr
;
1347 size_t curr_offset
, curr_end
;
1349 curr_offset
= max(BPDT_MIN_SIZE
, buffer_size(&ifwi_image
.bpdt
));
1352 * There are two types of sub-partitions that need to be handled here:
1353 * 1. Sub-partitions that lie within the same 4K as BPDT
1354 * 2. Sub-partitions that lie outside the 4K of BPDT
1356 * For sub-partitions of type # 1, there is no requirement on the start
1357 * or end of the sub-partition. They need to be packed in without any
1358 * holes left in between. If there is any empty space left after the end
1359 * of the last sub-partition in 4K of BPDT, then that space needs to be
1360 * padded with FF bytes, but the size of the last sub-partition remains
1363 * For sub-partitions of type # 2, both the start and end should be a
1364 * multiple of 4K. If not, then it needs to be padded with FF bytes and
1365 * size adjusted such that the sub-partition ends on 4K boundary.
1368 /* #1 Sub-partitions that lie within same 4K as BPDT */
1369 struct buffer
*last_bpdt_buff
= &ifwi_image
.bpdt
;
1371 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1372 type
= bpdt_pack_order
[i
];
1373 curr
= find_entry_by_type(type
);
1375 if (!curr
|| curr
->size
== 0)
1378 if (!(subparts
[type
].attr
& LIES_WITHIN_BPDT_4K
))
1381 curr
->offset
= curr_offset
;
1382 curr_offset
= curr
->offset
+ curr
->size
;
1383 last_bpdt_buff
= &ifwi_image
.subpart_buf
[type
];
1384 DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
1385 type
, curr_offset
, curr
->offset
, curr
->size
,
1386 buffer_size(&ifwi_image
.subpart_buf
[type
]));
1389 /* Pad ff bytes if there is any empty space left in BPDT 4K */
1390 curr_end
= ALIGN(curr_offset
, 4 * KiB
);
1391 pad_buffer(last_bpdt_buff
,
1392 buffer_size(last_bpdt_buff
) + (curr_end
- curr_offset
));
1393 curr_offset
= curr_end
;
1395 /* #2 Sub-partitions that lie outside of BPDT 4K */
1396 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1397 type
= bpdt_pack_order
[i
];
1398 curr
= find_entry_by_type(type
);
1400 if (!curr
|| curr
->size
== 0)
1403 if (subparts
[type
].attr
& LIES_WITHIN_BPDT_4K
)
1406 assert(curr_offset
== ALIGN(curr_offset
, 4 * KiB
));
1407 curr
->offset
= curr_offset
;
1408 curr_end
= ALIGN(curr
->offset
+ curr
->size
, 4 * KiB
);
1409 curr
->size
= curr_end
- curr
->offset
;
1411 pad_buffer(&ifwi_image
.subpart_buf
[type
], curr
->size
);
1413 curr_offset
= curr_end
;
1414 DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
1415 type
, curr_offset
, curr
->offset
, curr
->size
,
1416 buffer_size(&ifwi_image
.subpart_buf
[type
]));
1420 * Update size of S-BPDT to include size of all non-critical
1423 * Assumption: S-BPDT always lies at the end of IFWI image.
1425 curr
= find_entry_by_type(S_BPDT_TYPE
);
1428 assert(curr_offset
== ALIGN(curr_offset
, 4 * KiB
));
1429 curr
->size
= curr_offset
- curr
->offset
;
1432 /* Convert all members of BPDT to little-endian format */
1433 static void bpdt_fixup_write_buffer(struct buffer
*buf
)
1435 struct bpdt
*s
= buffer_get(buf
);
1437 struct bpdt_header
*h
= &s
->h
;
1438 struct bpdt_entry
*e
= &s
->e
[0];
1440 size_t count
= h
->descriptor_count
;
1444 offset
= fix_member(s
, offset
, sizeof(h
->signature
));
1445 offset
= fix_member(s
, offset
, sizeof(h
->descriptor_count
));
1446 offset
= fix_member(s
, offset
, sizeof(h
->bpdt_version
));
1447 offset
= fix_member(s
, offset
, sizeof(h
->xor_redundant_block
));
1448 offset
= fix_member(s
, offset
, sizeof(h
->ifwi_version
));
1449 offset
= fix_member(s
, offset
, sizeof(h
->fit_tool_version
));
1453 for (i
= 0; i
< count
; i
++) {
1454 offset
= fix_member(s
, offset
, sizeof(e
[i
].type
));
1455 offset
= fix_member(s
, offset
, sizeof(e
[i
].flags
));
1456 offset
= fix_member(s
, offset
, sizeof(e
[i
].offset
));
1457 offset
= fix_member(s
, offset
, sizeof(e
[i
].size
));
1461 /* Write BPDT to output buffer after fixup */
1462 static void bpdt_write(struct buffer
*dst
, size_t offset
, struct buffer
*src
)
1464 bpdt_fixup_write_buffer(src
);
1465 memcpy(buffer_get(dst
) + offset
, buffer_get(src
), buffer_size(src
));
1469 * Follows these steps to re-create image:
1470 * 1. Write any non-IFWI prefix.
1471 * 2. Write out BPDT header and entries.
1472 * 3. Write sub-partition buffers to respective offsets.
1473 * 4. Write any non-IFWI suffix.
1475 * While performing the above steps, make sure that any empty holes are filled
1478 static void ifwi_write(const char *image_name
)
1480 struct bpdt_entry
*s
= find_entry_by_type(S_BPDT_TYPE
);
1484 size_t ifwi_start
, ifwi_end
, file_end
;
1486 ifwi_start
= ifwi_image
.input_ifwi_start_offset
;
1487 ifwi_end
= ifwi_start
+ ALIGN(s
->offset
+ s
->size
, 4 * KiB
);
1488 file_end
= ifwi_end
+ (buffer_size(&ifwi_image
.input_buff
) -
1489 ifwi_image
.input_ifwi_end_offset
);
1493 alloc_buffer(&b
, file_end
, "Final-IFWI");
1495 uint8_t *input_data
= buffer_get(&ifwi_image
.input_buff
);
1496 uint8_t *output_data
= buffer_get(&b
);
1498 DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start
,
1499 ifwi_end
, file_end
);
1501 /* Copy non-IFWI prefix, if any */
1502 memcpy(output_data
, input_data
, ifwi_start
);
1504 DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start
);
1508 buffer_splice(&ifwi
, &b
, ifwi_start
, ifwi_end
- ifwi_start
);
1509 uint8_t *ifwi_data
= buffer_get(&ifwi
);
1511 /* Copy sub-partitions using pack_order */
1512 struct bpdt_entry
*curr
;
1513 struct buffer
*subpart_buf
;
1516 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1517 type
= bpdt_pack_order
[i
];
1519 if (type
== S_BPDT_TYPE
)
1522 curr
= find_entry_by_type(type
);
1524 if (!curr
|| !curr
->size
)
1527 subpart_buf
= &ifwi_image
.subpart_buf
[type
];
1529 DEBUG("curr->offset=0x%x, curr->size=0x%x, type=%d, write_size=0x%zx\n",
1530 curr
->offset
, curr
->size
, type
, buffer_size(subpart_buf
));
1532 assert((curr
->offset
+ buffer_size(subpart_buf
)) <=
1533 buffer_size(&ifwi
));
1535 memcpy(ifwi_data
+ curr
->offset
, buffer_get(subpart_buf
),
1536 buffer_size(subpart_buf
));
1539 /* Copy non-IFWI suffix, if any */
1540 if (ifwi_end
!= file_end
) {
1541 memcpy(output_data
+ ifwi_end
,
1542 input_data
+ ifwi_image
.input_ifwi_end_offset
,
1543 file_end
- ifwi_end
);
1544 DEBUG("Copied non-IFWI suffix (offset=0x%zx,size=0x%zx).\n",
1545 ifwi_end
, file_end
- ifwi_end
);
1549 * Convert BPDT to little-endian format and write it to output buffer.
1550 * S-BPDT is written first and then BPDT.
1552 bpdt_write(&ifwi
, s
->offset
, &ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
1553 bpdt_write(&ifwi
, 0, &ifwi_image
.bpdt
);
1555 if (buffer_write_file(&b
, image_name
)) {
1556 ERROR("File write error\n");
1561 printf("Image written successfully to %s.\n", image_name
);
1565 * Calculate size and offset of each sub-partition again since it might have
1566 * changed because of add/delete operation. Also, re-create BPDT and S-BPDT
1567 * entries and write back the new IFWI image to file.
1569 static void ifwi_repack(void)
1572 bpdt_entries_init_header_order();
1573 bpdt_entries_init_pack_order();
1575 struct bpdt
*b
= buffer_get(&ifwi_image
.bpdt
);
1577 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "BPDT");
1579 b
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
1580 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "S-BPDT");
1582 DEBUG("Repack done.. writing image.\n");
1583 ifwi_write(param
.image_name
);
1586 static void init_subpart_dir_header(struct subpart_dir_header
*hdr
,
1587 size_t count
, const char *name
)
1589 memset(hdr
, 0, sizeof(*hdr
));
1591 hdr
->marker
= SUBPART_DIR_MARKER
;
1592 hdr
->num_entries
= count
;
1593 hdr
->header_version
= SUBPART_DIR_HEADER_VERSION_SUPPORTED
;
1594 hdr
->entry_version
= SUBPART_DIR_ENTRY_VERSION_SUPPORTED
;
1595 hdr
->header_length
= SUBPART_DIR_HEADER_SIZE
;
1596 memcpy(hdr
->name
, name
, sizeof(hdr
->name
));
1599 static size_t init_subpart_dir_entry(struct subpart_dir_entry
*e
,
1600 struct buffer
*b
, size_t offset
)
1602 memset(e
, 0, sizeof(*e
));
1604 assert(strlen(b
->name
) <= sizeof(e
->name
));
1605 strncpy((char *)e
->name
, (char *)b
->name
, sizeof(e
->name
));
1607 e
->length
= buffer_size(b
);
1609 return (offset
+ buffer_size(b
));
1612 static void init_manifest_header(struct manifest_header
*hdr
, size_t size
)
1614 memset(hdr
, 0, sizeof(*hdr
));
1616 hdr
->header_type
= 0x4;
1617 assert((MANIFEST_HDR_SIZE
% DWORD_SIZE
) == 0);
1618 hdr
->header_length
= MANIFEST_HDR_SIZE
/ DWORD_SIZE
;
1619 hdr
->header_version
= 0x10000;
1620 hdr
->vendor
= 0x8086;
1622 struct tm
*local_time
;
1626 curr_time
= time(NULL
);
1627 local_time
= localtime(&curr_time
);
1628 assert(local_time
!= NULL
);
1630 strftime(buffer
, sizeof(buffer
), "0x%Y%m%d", local_time
);
1631 hdr
->date
= strtoul(buffer
, NULL
, 16);
1633 assert((size
% DWORD_SIZE
) == 0);
1634 hdr
->size
= size
/ DWORD_SIZE
;
1635 hdr
->id
= MANIFEST_ID_MAGIC
;
1638 static void init_signed_pkg_info_ext(struct signed_pkg_info_ext
*ext
,
1639 size_t count
, const char *name
)
1641 memset(ext
, 0, sizeof(*ext
));
1643 ext
->ext_type
= SIGNED_PKG_INFO_EXT_TYPE
;
1644 ext
->ext_length
= SIGNED_PKG_INFO_EXT_SIZE
+ count
* MODULE_SIZE
;
1645 memcpy(ext
->name
, name
, sizeof(ext
->name
));
1648 static void subpart_dir_fixup_write_buffer(struct buffer
*buf
)
1650 struct subpart_dir
*s
= buffer_get(buf
);
1651 struct subpart_dir_header
*h
= &s
->h
;
1652 struct subpart_dir_entry
*e
= &s
->e
[0];
1654 size_t count
= h
->num_entries
;
1657 offset
= fix_member(s
, offset
, sizeof(h
->marker
));
1658 offset
= fix_member(s
, offset
, sizeof(h
->num_entries
));
1659 offset
= fix_member(s
, offset
, sizeof(h
->header_version
));
1660 offset
= fix_member(s
, offset
, sizeof(h
->entry_version
));
1661 offset
= fix_member(s
, offset
, sizeof(h
->header_length
));
1662 offset
= fix_member(s
, offset
, sizeof(h
->checksum
));
1663 offset
+= sizeof(h
->name
);
1667 for (i
= 0; i
< count
; i
++) {
1668 offset
+= sizeof(e
[i
].name
);
1669 offset
= fix_member(s
, offset
, sizeof(e
[i
].offset
));
1670 offset
= fix_member(s
, offset
, sizeof(e
[i
].length
));
1671 offset
= fix_member(s
, offset
, sizeof(e
[i
].rsvd
));
1675 static void create_subpart(struct buffer
*dst
, struct buffer
*info
[],
1676 size_t count
, const char *name
)
1678 struct buffer subpart_dir_buff
;
1679 size_t size
= SUBPART_DIR_HEADER_SIZE
+ count
* SUBPART_DIR_ENTRY_SIZE
;
1681 alloc_buffer(&subpart_dir_buff
, size
, "subpart-dir");
1683 struct subpart_dir_header
*h
= buffer_get(&subpart_dir_buff
);
1684 struct subpart_dir_entry
*e
= (struct subpart_dir_entry
*)(h
+ 1);
1686 init_subpart_dir_header(h
, count
, name
);
1688 size_t curr_offset
= size
;
1691 for (i
= 0; i
< count
; i
++) {
1692 curr_offset
= init_subpart_dir_entry(&e
[i
], info
[i
],
1696 alloc_buffer(dst
, curr_offset
, name
);
1697 uint8_t *data
= buffer_get(dst
);
1699 for (i
= 0; i
< count
; i
++) {
1700 memcpy(data
+ e
[i
].offset
, buffer_get(info
[i
]),
1701 buffer_size(info
[i
]));
1704 h
->checksum
= calc_checksum(buffer_get(&subpart_dir_buff
));
1706 struct subpart_dir
*dir
= buffer_get(&subpart_dir_buff
);
1708 print_subpart_dir(dir
);
1710 subpart_dir_fixup_write_buffer(&subpart_dir_buff
);
1711 memcpy(data
, dir
, buffer_size(&subpart_dir_buff
));
1713 buffer_delete(&subpart_dir_buff
);
1716 static enum ifwi_ret
ibbp_dir_add(int type
)
1718 struct buffer manifest
;
1719 struct signed_pkg_info_ext
*ext
;
1723 #define DUMMY_IBB_SIZE (4 * KiB)
1725 assert(type
== IBB_TYPE
);
1728 * Entry # 1 - IBBP.man
1729 * Contains manifest header and signed pkg info extension.
1731 size_t size
= MANIFEST_HDR_SIZE
+ SIGNED_PKG_INFO_EXT_SIZE
;
1733 alloc_buffer(&manifest
, size
, "IBBP.man");
1735 struct manifest_header
*man_hdr
= buffer_get(&manifest
);
1737 init_manifest_header(man_hdr
, size
);
1739 ext
= (struct signed_pkg_info_ext
*)(man_hdr
+ 1);
1741 init_signed_pkg_info_ext(ext
, 0, subparts
[type
].name
);
1743 /* Entry # 2 - IBBL */
1744 if (buffer_from_file(&ibbl
, param
.file_name
))
1747 /* Entry # 3 - IBB */
1748 alloc_buffer(&ibb
, DUMMY_IBB_SIZE
, "IBB");
1749 memset(buffer_get(&ibb
), 0xFF, DUMMY_IBB_SIZE
);
1751 /* Create subpartition */
1752 struct buffer
*info
[] = {
1753 &manifest
, &ibbl
, &ibb
,
1755 create_subpart(&ifwi_image
.subpart_buf
[type
], &info
[0],
1756 ARRAY_SIZE(info
), subparts
[type
].name
);
1758 return REPACK_REQUIRED
;
1761 static enum ifwi_ret
ifwi_raw_add(int type
)
1763 if (buffer_from_file(&ifwi_image
.subpart_buf
[type
], param
.file_name
))
1766 printf("Sub-partition %s(%d) added from file %s.\n", param
.subpart_name
,
1767 type
, param
.file_name
);
1768 return REPACK_REQUIRED
;
1771 static enum ifwi_ret
ifwi_dir_add(int type
)
1773 if (!(subparts
[type
].attr
& CONTAINS_DIR
) ||
1774 !subparts
[type
].dir_ops
.dir_add
) {
1775 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1776 subparts
[type
].name
, type
);
1780 if (!param
.dentry_name
) {
1781 ERROR("%s: -e option required\n", __func__
);
1785 enum ifwi_ret ret
= subparts
[type
].dir_ops
.dir_add(type
);
1787 if (ret
!= COMMAND_ERR
)
1788 printf("Sub-partition %s(%d) entry %s added from file %s.\n",
1789 param
.subpart_name
, type
, param
.dentry_name
,
1792 ERROR("Sub-partition dir operation failed.\n");
1797 static enum ifwi_ret
ifwi_add(void)
1799 if (!param
.file_name
) {
1800 ERROR("%s: -f option required\n", __func__
);
1804 if (!param
.subpart_name
) {
1805 ERROR("%s: -n option required\n", __func__
);
1809 int type
= find_type_by_name(param
.subpart_name
);
1814 const struct subpart_info
*curr_subpart
= &subparts
[type
];
1816 if (curr_subpart
->attr
& AUTO_GENERATED
) {
1817 ERROR("Cannot add auto-generated sub-partitions.\n");
1821 if (buffer_size(&ifwi_image
.subpart_buf
[type
])) {
1822 ERROR("Image already contains sub-partition %s(%d).\n",
1823 param
.subpart_name
, type
);
1828 return ifwi_dir_add(type
);
1830 return ifwi_raw_add(type
);
1833 static enum ifwi_ret
ifwi_delete(void)
1835 if (!param
.subpart_name
) {
1836 ERROR("%s: -n option required\n", __func__
);
1840 int type
= find_type_by_name(param
.subpart_name
);
1845 const struct subpart_info
*curr_subpart
= &subparts
[type
];
1847 if (curr_subpart
->attr
& AUTO_GENERATED
) {
1848 ERROR("Cannot delete auto-generated sub-partitions.\n");
1852 if (buffer_size(&ifwi_image
.subpart_buf
[type
]) == 0) {
1853 printf("Image does not contain sub-partition %s(%d).\n",
1854 param
.subpart_name
, type
);
1855 return NO_ACTION_REQUIRED
;
1858 buffer_delete(&ifwi_image
.subpart_buf
[type
]);
1859 printf("Sub-Partition %s(%d) deleted.\n", subparts
[type
].name
, type
);
1860 return REPACK_REQUIRED
;
1863 static enum ifwi_ret
ifwi_dir_extract(int type
)
1865 if (!(subparts
[type
].attr
& CONTAINS_DIR
)) {
1866 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1867 subparts
[type
].name
, type
);
1871 if (!param
.dentry_name
) {
1872 ERROR("%s: -e option required.\n", __func__
);
1876 struct buffer subpart_dir_buff
;
1878 parse_subpart_dir(&subpart_dir_buff
, &ifwi_image
.subpart_buf
[type
],
1879 subparts
[type
].name
);
1882 struct subpart_dir
*s
= buffer_get(&subpart_dir_buff
);
1884 for (i
= 0; i
< s
->h
.num_entries
; i
++) {
1885 if (!strncmp((char *)s
->e
[i
].name
, param
.dentry_name
,
1886 sizeof(s
->e
[i
].name
)))
1890 if (i
== s
->h
.num_entries
) {
1891 ERROR("Entry %s not found in subpartition for %s.\n",
1892 param
.dentry_name
, param
.subpart_name
);
1898 DEBUG("Splicing buffer at 0x%x size 0x%x\n", s
->e
[i
].offset
,
1900 buffer_splice(&dst
, &ifwi_image
.subpart_buf
[type
], s
->e
[i
].offset
,
1903 if (buffer_write_file(&dst
, param
.file_name
))
1906 printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1907 param
.subpart_name
, type
, param
.dentry_name
, param
.file_name
);
1909 return NO_ACTION_REQUIRED
;
1912 static enum ifwi_ret
ifwi_raw_extract(int type
)
1914 if (buffer_write_file(&ifwi_image
.subpart_buf
[type
], param
.file_name
))
1917 printf("Sub-Partition %s(%d) stored in %s.\n", param
.subpart_name
, type
,
1920 return NO_ACTION_REQUIRED
;
1923 static enum ifwi_ret
ifwi_extract(void)
1925 if (!param
.file_name
) {
1926 ERROR("%s: -f option required\n", __func__
);
1930 if (!param
.subpart_name
) {
1931 ERROR("%s: -n option required\n", __func__
);
1935 int type
= find_type_by_name(param
.subpart_name
);
1940 if (type
== S_BPDT_TYPE
) {
1941 INFO("Tool does not support raw extract for %s\n",
1942 param
.subpart_name
);
1943 return NO_ACTION_REQUIRED
;
1946 if (buffer_size(&ifwi_image
.subpart_buf
[type
]) == 0) {
1947 ERROR("Image does not contain sub-partition %s(%d).\n",
1948 param
.subpart_name
, type
);
1952 INFO("Extracting sub-partition %s(%d).\n", param
.subpart_name
, type
);
1954 return ifwi_dir_extract(type
);
1956 return ifwi_raw_extract(type
);
1959 static enum ifwi_ret
ifwi_print(void)
1963 struct bpdt
*b
= buffer_get(&ifwi_image
.bpdt
);
1965 bpdt_print_header(&b
->h
, "BPDT");
1966 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "BPDT");
1968 b
= buffer_get(&ifwi_image
.subpart_buf
[S_BPDT_TYPE
]);
1969 bpdt_print_header(&b
->h
, "S-BPDT");
1970 bpdt_print_entries(&b
->e
[0], b
->h
.descriptor_count
, "S-BPDT");
1972 if (param
.dir_ops
== 0) {
1974 return NO_ACTION_REQUIRED
;
1978 struct buffer subpart_dir_buf
;
1980 for (i
= 0; i
< MAX_SUBPARTS
; i
++) {
1981 if (!(subparts
[i
].attr
& CONTAINS_DIR
) ||
1982 (buffer_size(&ifwi_image
.subpart_buf
[i
]) == 0))
1985 parse_subpart_dir(&subpart_dir_buf
, &ifwi_image
.subpart_buf
[i
],
1987 buffer_delete(&subpart_dir_buf
);
1992 return NO_ACTION_REQUIRED
;
1995 static enum ifwi_ret
ifwi_raw_replace(int type
)
1997 buffer_delete(&ifwi_image
.subpart_buf
[type
]);
1998 return ifwi_raw_add(type
);
2001 static enum ifwi_ret
ifwi_dir_replace(int type
)
2003 if (!(subparts
[type
].attr
& CONTAINS_DIR
)) {
2004 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
2005 subparts
[type
].name
, type
);
2009 if (!param
.dentry_name
) {
2010 ERROR("%s: -e option required.\n", __func__
);
2014 struct buffer subpart_dir_buf
;
2016 parse_subpart_dir(&subpart_dir_buf
, &ifwi_image
.subpart_buf
[type
],
2017 subparts
[type
].name
);
2020 struct subpart_dir
*s
= buffer_get(&subpart_dir_buf
);
2022 for (i
= 0; i
< s
->h
.num_entries
; i
++) {
2023 if (!strcmp((char *)s
->e
[i
].name
, param
.dentry_name
))
2027 if (i
== s
->h
.num_entries
) {
2028 ERROR("Entry %s not found in subpartition for %s.\n",
2029 param
.dentry_name
, param
.subpart_name
);
2035 if (buffer_from_file(&b
, param
.file_name
)) {
2036 ERROR("Failed to read %s\n", param
.file_name
);
2041 size_t dst_size
= buffer_size(&ifwi_image
.subpart_buf
[type
]) +
2042 buffer_size(&b
) - s
->e
[i
].length
;
2043 size_t subpart_start
= s
->e
[i
].offset
;
2044 size_t subpart_end
= s
->e
[i
].offset
+ s
->e
[i
].length
;
2046 alloc_buffer(&dst
, dst_size
, ifwi_image
.subpart_buf
[type
].name
);
2048 uint8_t *src_data
= buffer_get(&ifwi_image
.subpart_buf
[type
]);
2049 uint8_t *dst_data
= buffer_get(&dst
);
2050 size_t curr_offset
= 0;
2052 /* Copy data before the sub-partition entry */
2053 memcpy(dst_data
+ curr_offset
, src_data
, subpart_start
);
2054 curr_offset
+= subpart_start
;
2056 /* Copy sub-partition entry */
2057 memcpy(dst_data
+ curr_offset
, buffer_get(&b
), buffer_size(&b
));
2058 curr_offset
+= buffer_size(&b
);
2060 /* Copy remaining data */
2061 memcpy(dst_data
+ curr_offset
, src_data
+ subpart_end
,
2062 buffer_size(&ifwi_image
.subpart_buf
[type
]) - subpart_end
);
2064 /* Update sub-partition buffer */
2065 int offset
= s
->e
[i
].offset
;
2067 buffer_delete(&ifwi_image
.subpart_buf
[type
]);
2068 ifwi_image
.subpart_buf
[type
] = dst
;
2070 /* Update length of entry in the subpartition */
2071 s
->e
[i
].length
= buffer_size(&b
);
2074 /* Adjust offsets of affected entries in subpartition */
2075 offset
= s
->e
[i
].offset
- offset
;
2076 for (; i
< s
->h
.num_entries
; i
++)
2077 s
->e
[i
].offset
+= offset
;
2079 /* Re-calculate checksum */
2080 s
->h
.checksum
= calc_checksum(s
);
2082 /* Convert members to litte-endian */
2083 subpart_dir_fixup_write_buffer(&subpart_dir_buf
);
2085 memcpy(dst_data
, buffer_get(&subpart_dir_buf
),
2086 buffer_size(&subpart_dir_buf
));
2088 buffer_delete(&subpart_dir_buf
);
2090 printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
2091 param
.subpart_name
, type
, param
.dentry_name
, param
.file_name
);
2093 return REPACK_REQUIRED
;
2096 static enum ifwi_ret
ifwi_replace(void)
2098 if (!param
.file_name
) {
2099 ERROR("%s: -f option required\n", __func__
);
2103 if (!param
.subpart_name
) {
2104 ERROR("%s: -n option required\n", __func__
);
2108 int type
= find_type_by_name(param
.subpart_name
);
2113 const struct subpart_info
*curr_subpart
= &subparts
[type
];
2115 if (curr_subpart
->attr
& AUTO_GENERATED
) {
2116 ERROR("Cannot replace auto-generated sub-partitions.\n");
2120 if (buffer_size(&ifwi_image
.subpart_buf
[type
]) == 0) {
2121 ERROR("Image does not contain sub-partition %s(%d).\n",
2122 param
.subpart_name
, type
);
2127 return ifwi_dir_replace(type
);
2129 return ifwi_raw_replace(type
);
2132 static enum ifwi_ret
ifwi_create(void)
2135 * Create peels off any non-IFWI content present in the input buffer and
2136 * creates output file with only the IFWI present.
2139 if (!param
.file_name
) {
2140 ERROR("%s: -f option required\n", __func__
);
2144 /* Peel off any non-IFWI prefix */
2145 buffer_seek(&ifwi_image
.input_buff
,
2146 ifwi_image
.input_ifwi_start_offset
);
2147 /* Peel off any non-IFWI suffix */
2148 buffer_set_size(&ifwi_image
.input_buff
,
2149 ifwi_image
.input_ifwi_end_offset
-
2150 ifwi_image
.input_ifwi_start_offset
);
2153 * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
2155 ifwi_image
.input_ifwi_end_offset
-= ifwi_image
.input_ifwi_start_offset
;
2156 ifwi_image
.input_ifwi_start_offset
= 0;
2158 param
.image_name
= param
.file_name
;
2160 return REPACK_REQUIRED
;
2165 const char *optstring
;
2166 enum ifwi_ret (*function
)(void);
2169 static const struct command commands
[] = {
2170 {"add", "f:n:e:dvh?", ifwi_add
},
2171 {"create", "f:vh?", ifwi_create
},
2172 {"delete", "f:n:vh?", ifwi_delete
},
2173 {"extract", "f:n:e:dvh?", ifwi_extract
},
2174 {"print", "dh?", ifwi_print
},
2175 {"replace", "f:n:e:dvh?", ifwi_replace
},
2178 static struct option long_options
[] = {
2179 {"subpart_dentry", required_argument
, 0, 'e'},
2180 {"file", required_argument
, 0, 'f'},
2181 {"help", required_argument
, 0, 'h'},
2182 {"name", required_argument
, 0, 'n'},
2183 {"dir_ops", no_argument
, 0, 'd'},
2184 {"verbose", no_argument
, 0, 'v'},
2188 static void usage(const char *name
)
2190 printf("ifwitool: Utility for IFWI manipulation\n\n"
2193 " %s FILE COMMAND [PARAMETERS]\n\n"
2195 " add -f FILE -n NAME [-d -e ENTRY]\n"
2198 " extract -f FILE -n NAME [-d -e ENTRY]\n"
2200 " replace -f FILE -n NAME [-d -e ENTRY]\n"
2202 " -f FILE : File to read/write/create/extract\n"
2203 " -d : Perform directory operation\n"
2204 " -e ENTRY: Name of directory entry to operate on\n"
2205 " -v : Verbose level\n"
2206 " -h : Help message\n"
2207 " -n NAME : Name of sub-partition to operate on\n",
2211 printf("\nNAME should be one of:\n");
2214 for (i
= 0; i
< MAX_SUBPARTS
; i
++)
2215 printf("%s(%s)\n", subparts
[i
].name
, subparts
[i
].readable_name
);
2219 int main(int argc
, char **argv
)
2226 param
.image_name
= argv
[1];
2227 char *cmd
= argv
[2];
2233 for (i
= 0; i
< ARRAY_SIZE(commands
); i
++) {
2234 if (strcmp(cmd
, commands
[i
].name
) != 0)
2242 c
= getopt_long(argc
, argv
, commands
[i
].optstring
,
2243 long_options
, &option_index
);
2248 /* Filter out illegal long options */
2249 if (!strchr(commands
[i
].optstring
, c
)) {
2250 ERROR("%s: invalid option -- '%c'\n", argv
[0],
2257 param
.subpart_name
= optarg
;
2260 param
.file_name
= optarg
;
2266 param
.dentry_name
= optarg
;
2281 ERROR("%s: ifwi parsing failed\n", argv
[0]);
2285 enum ifwi_ret ret
= commands
[i
].function();
2287 if (ret
== COMMAND_ERR
) {
2288 ERROR("%s: failed execution\n", argv
[0]);
2292 if (ret
== REPACK_REQUIRED
)
2298 ERROR("%s: invalid command\n", argv
[0]);