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 uint8_t *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]);