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 "os_support.h"
14 #define __packed __attribute__((packed))
17 #define ALIGN(x, a) __ALIGN_MASK((x), (typeof(x))(a) - 1)
18 #define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask))
19 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
22 * min()/max()/clamp() macros that also do
23 * strict type-checking.. See the
24 * "unnecessary" pointer comparison.
26 #define min(x, y) ({ \
27 typeof(x) _min1 = (x); \
28 typeof(y) _min2 = (y); \
29 (void)&_min1 == &_min2); \
30 _min1 < _min2 ? _min1 : _min2; })
32 #define max(x, y) ({ \
33 typeof(x) _max1 = (x); \
34 typeof(y) _max2 = (y); \
35 (void)(&_max1 == &_max2); \
36 _max1 > _max2 ? _max1 : _max2; })
38 static int verbose = 1;
40 /* Buffer and file I/O */
48 #define ERROR(...) { fprintf(stderr, "E: " __VA_ARGS__); }
49 #define INFO(...) { if (verbose > 0) fprintf(stderr, "INFO: " __VA_ARGS__); }
50 #define DEBUG(...) { if (verbose > 1) fprintf(stderr, "DEBUG: " __VA_ARGS__); }
53 * BPDT is Boot Partition Descriptor Table. It is located at the start of a
54 * logical boot partition(LBP). It stores information about the critical
55 * sub-partitions present within the LBP.
57 * S-BPDT is Secondary Boot Partition Descriptor Table. It is located after the
58 * critical sub-partitions and contains information about the non-critical
59 * sub-partitions present within the LBP.
61 * Both tables are identified by BPDT_SIGNATURE stored at the start of the
64 #define BPDT_SIGNATURE (0x000055AA)
66 /* Parameters passed in by caller */
68 const char *file_name;
69 const char *subpart_name;
70 const char *image_name;
72 const char *dentry_name;
77 * This is used to identify start of BPDT. It should always be
81 /* Count of BPDT entries present */
82 uint16_t descriptor_count;
83 /* Version - Currently supported = 1 */
84 uint16_t bpdt_version;
85 /* Unused - Should be 0 */
86 uint32_t xor_redundant_block;
87 /* Version of IFWI build */
88 uint32_t ifwi_version;
89 /* Version of FIT tool used to create IFWI */
90 uint64_t fit_tool_version;
92 #define BPDT_HEADER_SIZE (sizeof(struct bpdt_header))
95 /* Type of sub-partition */
97 /* Attributes of sub-partition */
99 /* Offset of sub-partition from beginning of LBP */
101 /* Size in bytes of sub-partition */
104 #define BPDT_ENTRY_SIZE (sizeof(struct bpdt_entry))
107 struct bpdt_header h;
108 /* In practice, this could be an array of 0 to n entries */
109 struct bpdt_entry e[0];
112 static inline size_t get_bpdt_size(struct bpdt_header *h)
114 return (sizeof(*h) + BPDT_ENTRY_SIZE * h->descriptor_count);
117 /* Minimum size in bytes allocated to BPDT in IFWI */
118 #define BPDT_MIN_SIZE ((size_t)512)
120 /* Header to define directory header for sub-partition */
121 struct subpart_dir_header {
122 /* Should be SUBPART_DIR_MARKER */
124 /* Number of directory entries in the sub-partition */
125 uint32_t num_entries;
126 /* Currenty supported - 1 */
127 uint8_t header_version;
128 /* Currenty supported - 1 */
129 uint8_t entry_version;
130 /* Length of directory header in bytes */
131 uint8_t header_length;
133 * 2s complement of 8-bit sum from first byte of header to last byte of
134 * last directory entry.
137 /* ASCII short name of sub-partition */
140 #define SUBPART_DIR_HEADER_SIZE \
141 (sizeof(struct subpart_dir_header))
142 #define SUBPART_DIR_MARKER 0x44504324
143 #define SUBPART_DIR_HEADER_VERSION_SUPPORTED 1
144 #define SUBPART_DIR_ENTRY_VERSION_SUPPORTED 1
146 /* Structure for each directory entry for sub-partition */
147 struct subpart_dir_entry {
148 /* Name of directory entry - Not guaranteed to be NULL-terminated */
150 /* Offset of entry from beginning of sub-partition */
152 /* Length in bytes of sub-directory entry */
157 #define SUBPART_DIR_ENTRY_SIZE \
158 (sizeof(struct subpart_dir_entry))
161 struct subpart_dir_header h;
162 /* In practice, this could be an array of 0 to n entries */
163 struct subpart_dir_entry e[0];
166 static inline size_t subpart_dir_size(struct subpart_dir_header *h)
168 return (sizeof(*h) + SUBPART_DIR_ENTRY_SIZE * h->num_entries);
171 struct manifest_header {
172 uint32_t header_type;
173 uint32_t header_length;
174 uint32_t header_version;
185 uint32_t modulus_size;
186 uint32_t exponent_size;
187 uint8_t public_key[256];
189 uint8_t signature[256];
193 #define MANIFEST_HDR_SIZE (sizeof(struct manifest_header))
194 #define MANIFEST_ID_MAGIC (0x324e4d24)
201 uint32_t metadata_size;
202 uint8_t metadata_hash[32];
205 #define MODULE_SIZE (sizeof(struct module))
207 struct signed_pkg_info_ext {
217 #define SIGNED_PKG_INFO_EXT_TYPE 0x15
218 #define SIGNED_PKG_INFO_EXT_SIZE \
219 (sizeof(struct signed_pkg_info_ext))
222 * Attributes for various IFWI sub-partitions.
223 * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
225 * NON_CRITICAL_SUBPART = Sub-Partition entry should be present in S-BPDT.
226 * CONTAINS_DIR = Sub-Partition contains directory.
227 * AUTO_GENERATED = Sub-Partition is generated by the tool.
228 * MANDATORY_BPDT_ENTRY = Even if sub-partition is deleted, BPDT should contain
229 * an entry for it with size 0 and offset 0.
231 enum subpart_attributes {
232 LIES_WITHIN_BPDT_4K = (1 << 0),
233 NON_CRITICAL_SUBPART = (1 << 1),
234 CONTAINS_DIR = (1 << 2),
235 AUTO_GENERATED = (1 << 3),
236 MANDATORY_BPDT_ENTRY = (1 << 4),
239 /* Type value for various IFWI sub-partitions */
240 enum bpdt_entry_type {
251 IFP_OVERRIDE_TYPE = 10,
252 DEBUG_TOKENS_TYPE = 11,
257 NVM_CONFIG_TYPE = 16,
259 UFS_RATE_B_TYPE = 18,
264 * There are two order requirements for an IFWI image:
265 * 1. Order in which the sub-partitions lie within the BPDT entries.
266 * 2. Order in which the sub-partitions lie within the image.
268 * header_order defines #1 i.e. the order in which the sub-partitions should
269 * appear in the BPDT entries. pack_order defines #2 i.e. the order in which
270 * sub-partitions appear in the IFWI image. pack_order controls the offset and
271 * thus sub-partitions would have increasing offsets as we loop over pack_order.
273 const enum bpdt_entry_type bpdt_header_order[MAX_SUBPARTS] = {
274 /* Order of the following entries is mandatory */
281 /* Order of the following entries is recommended */
297 const enum bpdt_entry_type bpdt_pack_order[MAX_SUBPARTS] = {
298 /* Order of the following entries is mandatory */
305 /* Order of the following entries is recommended */
321 /* Utility functions */
324 NO_ACTION_REQUIRED = 0,
329 enum ifwi_ret (*dir_add)(int type);
332 static enum ifwi_ret ibbp_dir_add(int type);
334 const struct subpart_info {
336 const char *readable_name;
338 struct dir_ops dir_ops;
339 } subparts[MAX_SUBPARTS] = {
341 [SMIP_TYPE] = {"SMIP", "SMIP", CONTAINS_DIR, {NULL} },
343 [CSE_RBE_TYPE] = {"RBEP", "CSE_RBE", CONTAINS_DIR |
344 MANDATORY_BPDT_ENTRY, {NULL} },
346 [CSE_BUP_TYPE] = {"FTPR", "CSE_BUP", CONTAINS_DIR |
347 MANDATORY_BPDT_ENTRY, {NULL} },
349 [UCODE_TYPE] = {"UCOD", "Microcode", CONTAINS_DIR, {NULL} },
351 [IBB_TYPE] = {"IBBP", "Bootblock", CONTAINS_DIR, {ibbp_dir_add} },
353 [S_BPDT_TYPE] = {"S_BPDT", "S-BPDT", AUTO_GENERATED |
354 MANDATORY_BPDT_ENTRY, {NULL} },
356 [OBB_TYPE] = {"OBBP", "OEM boot block", CONTAINS_DIR |
357 NON_CRITICAL_SUBPART, {NULL} },
359 [CSE_MAIN_TYPE] = {"NFTP", "CSE_MAIN", CONTAINS_DIR |
360 NON_CRITICAL_SUBPART, {NULL} },
362 [ISH_TYPE] = {"ISHP", "ISH", NON_CRITICAL_SUBPART, {NULL} },
364 [CSE_IDLM_TYPE] = {"DLMP", "CSE_IDLM", CONTAINS_DIR |
365 MANDATORY_BPDT_ENTRY, {NULL} },
367 [IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
368 LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
371 [DEBUG_TOKENS_TYPE] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL} },
372 /* UFS Phy Configuration */
373 [UFS_PHY_TYPE] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K |
374 MANDATORY_BPDT_ENTRY, {NULL} },
376 [UFS_GPP_TYPE] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K |
377 MANDATORY_BPDT_ENTRY, {NULL} },
379 [PMC_TYPE] = {"PMCP", "PMC firmware", CONTAINS_DIR, {NULL} },
381 [IUNIT_TYPE] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART, {NULL} },
383 [NVM_CONFIG_TYPE] = {"NVM_CONFIG", "NVM Config", 0, {NULL} },
385 [UEP_TYPE] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
387 /* UFS Rate B Config */
388 [UFS_RATE_B_TYPE] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL} },
392 /* Data read from input file */
393 struct buffer input_buff;
395 /* BPDT header and entries */
397 size_t input_ifwi_start_offset;
398 size_t input_ifwi_end_offset;
400 /* Subpartition content */
401 struct buffer subpart_buf[MAX_SUBPARTS];
404 /* Buffer and file I/O */
405 static off_t get_file_size(FILE *f)
409 fseek(f, 0, SEEK_END);
411 fseek(f, 0, SEEK_SET);
415 static inline void *buffer_get(const struct buffer *b)
420 static inline size_t buffer_size(const struct buffer *b)
425 static inline size_t buffer_offset(const struct buffer *b)
431 * Shrink a buffer toward the beginning of its previous space.
432 * Afterward, buffer_delete() remains the means of cleaning it up
434 static inline void buffer_set_size(struct buffer *b, size_t size)
439 /* Splice a buffer into another buffer. Note that it's up to the caller to
440 * bounds check the offset and size. The resulting buffer is backed by the same
441 * storage as the original, so although it is valid to buffer_delete() either
442 * one of them, doing so releases both simultaneously
444 static void buffer_splice(struct buffer *dest, const struct buffer *src,
445 size_t offset, size_t size)
447 dest->name = src->name;
448 dest->data = src->data + offset;
449 dest->offset = src->offset + offset;
454 * Shrink a buffer toward the end of its previous space.
455 * Afterward, buffer_delete() remains the means of cleaning it up
457 static inline void buffer_seek(struct buffer *b, size_t size)
464 /* Returns the start of the underlying buffer, with the offset undone */
465 static inline void *buffer_get_original_backing(const struct buffer *b)
469 return buffer_get(b) - buffer_offset(b);
472 int buffer_create(struct buffer *buffer, size_t size, const char *name)
474 buffer->name = strdup(name);
477 buffer->data = (char *)malloc(buffer->size);
479 fprintf(stderr, "%s: Insufficient memory (0x%zx).\n", __func__,
483 return !buffer->data;
486 int buffer_write_file(struct buffer *buffer, const char *filename)
488 FILE *fp = fopen(filename, "wb");
494 assert(buffer && buffer->data);
495 if (fwrite(buffer->data, 1, buffer->size, fp) != buffer->size) {
496 fprintf(stderr, "incomplete write: %s\n", filename);
504 void buffer_delete(struct buffer *buffer)
512 free(buffer_get_original_backing(buffer));
519 int buffer_from_file(struct buffer *buffer, const char *filename)
521 FILE *fp = fopen(filename, "rb");
528 off_t file_size = get_file_size(fp);
531 fprintf(stderr, "could not determine size of %s\n", filename);
535 buffer->size = file_size;
536 buffer->name = strdup(filename);
537 buffer->data = (char *)malloc(buffer->size);
538 assert(buffer->data);
539 if (fread(buffer->data, 1, buffer->size, fp) != buffer->size) {
540 fprintf(stderr, "incomplete read: %s\n", filename);
542 buffer_delete(buffer);
549 static void alloc_buffer(struct buffer *b, size_t s, const char *n)
551 if (buffer_create(b, s, n) == 0)
554 ERROR("Buffer allocation failure for %s (size = %zx).\n", n, s);
558 /* Little-Endian functions */
559 static inline uint8_t read_ble8(const void *src)
561 const uint8_t *s = src;
565 static inline uint8_t read_at_ble8(const void *src, size_t offset)
567 const uint8_t *s = src;
573 static inline void write_ble8(void *dest, uint8_t val)
575 *(uint8_t *)dest = val;
578 static inline void write_at_ble8(void *dest, uint8_t val, size_t offset)
586 static inline uint8_t read_at_le8(const void *src, size_t offset)
588 return read_at_ble8(src, offset);
591 static inline void write_le8(void *dest, uint8_t val)
593 write_ble8(dest, val);
596 static inline void write_at_le8(void *dest, uint8_t val, size_t offset)
598 write_at_ble8(dest, val, offset);
601 static inline uint16_t read_le16(const void *src)
603 const uint8_t *s = src;
605 return (((uint16_t)s[1]) << 8) | (((uint16_t)s[0]) << 0);
608 static inline uint16_t read_at_le16(const void *src, size_t offset)
610 const uint8_t *s = src;
616 static inline void write_le16(void *dest, uint16_t val)
618 write_le8(dest, val >> 0);
619 write_at_le8(dest, val >> 8, sizeof(uint8_t));
622 static inline void write_at_le16(void *dest, uint16_t val, size_t offset)
630 static inline uint32_t read_le32(const void *src)
632 const uint8_t *s = src;
634 return (((uint32_t)s[3]) << 24) | (((uint32_t)s[2]) << 16) |
635 (((uint32_t)s[1]) << 8) | (((uint32_t)s[0]) << 0);
638 static inline uint32_t read_at_le32(const void *src, size_t offset)
640 const uint8_t *s = src;
646 static inline void write_le32(void *dest, uint32_t val)
648 write_le16(dest, val >> 0);
649 write_at_le16(dest, val >> 16, sizeof(uint16_t));
652 static inline void write_at_le32(void *dest, uint32_t val, size_t offset)
660 static inline uint64_t read_le64(const void *src)
664 val = read_at_le32(src, sizeof(uint32_t));
666 val |= read_le32(src);
670 static inline uint64_t read_at_le64(const void *src, size_t offset)
672 const uint8_t *s = src;
678 static inline void write_le64(void *dest, uint64_t val)
680 write_le32(dest, val >> 0);
681 write_at_le32(dest, val >> 32, sizeof(uint32_t));
684 static inline void write_at_le64(void *dest, uint64_t val, size_t offset)
693 * Read header/entry members in little-endian format.
694 * Returns the offset upto which the read was performed.
696 static size_t read_member(void *src, size_t offset, size_t size_bytes,
699 switch (size_bytes) {
701 *(uint8_t *)dst = read_at_le8(src, offset);
704 *(uint16_t *)dst = read_at_le16(src, offset);
707 *(uint32_t *)dst = read_at_le32(src, offset);
710 *(uint64_t *)dst = read_at_le64(src, offset);
713 ERROR("Read size not supported %zd\n", size_bytes);
717 return (offset + size_bytes);
721 * Convert to little endian format.
722 * Returns the offset upto which the fixup was performed.
724 static size_t fix_member(void *data, size_t offset, size_t size_bytes)
726 uint8_t *src = (uint8_t *)data + offset;
728 switch (size_bytes) {
730 write_at_le8(data, *(uint8_t *)src, offset);
733 write_at_le16(data, *(uint16_t *)src, offset);
736 write_at_le32(data, *(uint32_t *)src, offset);
739 write_at_le64(data, *(uint64_t *)src, offset);
742 ERROR("Write size not supported %zd\n", size_bytes);
745 return (offset + size_bytes);
748 static void print_subpart_dir(struct subpart_dir *s)
755 printf("%-25s 0x%-23.8x\n", "Marker", s->h.marker);
756 printf("%-25s %-25d\n", "Num entries", s->h.num_entries);
757 printf("%-25s %-25d\n", "Header Version", s->h.header_version);
758 printf("%-25s %-25d\n", "Entry Version", s->h.entry_version);
759 printf("%-25s 0x%-23x\n", "Header Length", s->h.header_length);
760 printf("%-25s 0x%-23x\n", "Checksum", s->h.checksum);
761 printf("%-25s ", "Name");
762 for (i = 0; i < sizeof(s->h.name); i++)
763 printf("%c", s->h.name[i]);
767 printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
770 printf("=========================================================================================================================\n");
772 for (i = 0; i < s->h.num_entries; i++) {
773 printf("%-25zd%-25.12s0x%-23x0x%-23x0x%-23x\n", i + 1,
774 s->e[i].name, s->e[i].offset, s->e[i].length,
778 printf("=========================================================================================================================\n");
781 static void bpdt_print_header(struct bpdt_header *h, const char *name)
786 printf("%-25s %-25s\n", "Header", name);
787 printf("%-25s 0x%-23.8x\n", "Signature", h->signature);
788 printf("%-25s %-25d\n", "Descriptor count", h->descriptor_count);
789 printf("%-25s %-25d\n", "BPDT Version", h->bpdt_version);
790 printf("%-25s 0x%-23x\n", "XOR checksum", h->xor_redundant_block);
791 printf("%-25s 0x%-23x\n", "IFWI Version", h->ifwi_version);
792 printf("%-25s 0x%-23llx\n", "FIT Tool Version",
793 (long long)h->fit_tool_version);
796 static void bpdt_print_entries(struct bpdt_entry *e, size_t count,
804 printf("%s entries\n", name);
806 printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
807 "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
810 printf("=========================================================================================================================================================================================================\n");
812 for (i = 0; i < count; i++) {
813 printf("%-25zd%-25s%-25s%-25d0x%-23.08x0x%-23x0x%-23x0x%-23zx\n",
814 i + 1, subparts[e[i].type].name,
815 subparts[e[i].type].readable_name, e[i].type, e[i].flags,
816 e[i].offset, e[i].size,
817 e[i].offset + ifwi_image.input_ifwi_start_offset);
820 printf("=========================================================================================================================================================================================================\n");
823 static void bpdt_validate_header(struct bpdt_header *h, const char *name)
825 assert(h->signature == BPDT_SIGNATURE);
827 if (h->bpdt_version != 1) {
828 ERROR("Invalid header : %s\n", name);
832 DEBUG("Validated header : %s\n", name);
835 static void bpdt_read_header(void *data, struct bpdt_header *h,
840 offset = read_member(data, offset, sizeof(h->signature), &h->signature);
841 offset = read_member(data, offset, sizeof(h->descriptor_count),
842 &h->descriptor_count);
843 offset = read_member(data, offset, sizeof(h->bpdt_version),
845 offset = read_member(data, offset, sizeof(h->xor_redundant_block),
846 &h->xor_redundant_block);
847 offset = read_member(data, offset, sizeof(h->ifwi_version),
849 read_member(data, offset, sizeof(h->fit_tool_version),
850 &h->fit_tool_version);
852 bpdt_validate_header(h, name);
853 bpdt_print_header(h, name);
856 static void bpdt_read_entries(void *data, struct bpdt *bpdt, const char *name)
858 size_t i, offset = 0;
859 struct bpdt_entry *e = &bpdt->e[0];
860 size_t count = bpdt->h.descriptor_count;
862 for (i = 0; i < count; i++) {
863 offset = read_member(data, offset, sizeof(e[i].type),
865 offset = read_member(data, offset, sizeof(e[i].flags),
867 offset = read_member(data, offset, sizeof(e[i].offset),
869 offset = read_member(data, offset, sizeof(e[i].size),
873 bpdt_print_entries(e, count, name);
877 * Given type of sub-partition, identify BPDT entry for it.
878 * Sub-Partition could lie either within BPDT or S-BPDT.
880 static struct bpdt_entry *__find_entry_by_type(struct bpdt_entry *e,
881 size_t count, int type)
885 for (i = 0; i < count; i++) {
886 if (e[i].type == type)
896 static struct bpdt_entry *find_entry_by_type(int type)
898 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
903 struct bpdt_entry *curr = __find_entry_by_type(&b->e[0],
904 b->h.descriptor_count,
910 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
914 return __find_entry_by_type(&b->e[0], b->h.descriptor_count, type);
918 * Find sub-partition type given its name. If the name does not exist, returns
921 static int find_type_by_name(const char *name)
925 for (i = 0; i < MAX_SUBPARTS; i++) {
926 if ((strlen(subparts[i].name) == strlen(name)) &&
927 (!strcmp(subparts[i].name, name)))
931 if (i == MAX_SUBPARTS) {
932 ERROR("Invalid sub-partition name %s.\n", name);
940 * Read the content of a sub-partition from input file and store it in
941 * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
943 * Returns the maximum offset occupied by the sub-partitions.
945 static size_t read_subpart_buf(void *data, size_t size, struct bpdt_entry *e,
950 size_t max_offset = 0;
952 for (i = 0; i < count; i++) {
955 if (type >= MAX_SUBPARTS) {
956 ERROR("Invalid sub-partition type %zd.\n", type);
960 if (buffer_size(&ifwi_image.subpart_buf[type])) {
961 ERROR("Multiple sub-partitions of type %zd(%s).\n",
962 type, subparts[type].name);
966 if (e[i].size == 0) {
967 INFO("Dummy sub-partition %zd(%s). Skipping.\n", type,
968 subparts[type].name);
972 assert((e[i].offset + e[i].size) <= size);
975 * Sub-partitions in IFWI image are not in the same order as
976 * in BPDT entries. BPDT entires are in header_order whereas
977 * sub-partition offsets in the image are in pack_order.
979 if ((e[i].offset + e[i].size) > max_offset)
980 max_offset = e[i].offset + e[i].size;
983 * S-BPDT sub-partition contains information about all the
984 * non-critical sub-partitions. Thus, size of S-BPDT
985 * sub-partition equals size of S-BPDT plus size of all the
986 * non-critical sub-partitions. Thus, reading whole of S-BPDT
987 * here would be redundant as the non-critical partitions are
988 * read and allocated buffers separately. Also, S-BPDT requires
989 * special handling for reading header and entries.
991 if (type == S_BPDT_TYPE)
994 buf = &ifwi_image.subpart_buf[type];
996 alloc_buffer(buf, e[i].size, subparts[type].name);
997 memcpy(buffer_get(buf), (uint8_t *)data + e[i].offset,
1006 * Allocate buffer for bpdt header, entries and all sub-partition content.
1007 * Returns offset in data where BPDT ends.
1009 static size_t alloc_bpdt_buffer(void *data, size_t size, size_t offset,
1010 struct buffer *b, const char *name)
1012 struct bpdt_header bpdt_header;
1014 assert((offset + BPDT_HEADER_SIZE) < size);
1015 bpdt_read_header((uint8_t *)data + offset, &bpdt_header, name);
1017 /* Buffer to read BPDT header and entries */
1018 alloc_buffer(b, get_bpdt_size(&bpdt_header), name);
1020 struct bpdt *bpdt = buffer_get(b);
1022 memcpy(&bpdt->h, &bpdt_header, BPDT_HEADER_SIZE);
1025 * If no entries are present, maximum offset occupied is (offset +
1026 * BPDT_HEADER_SIZE).
1028 if (bpdt->h.descriptor_count == 0)
1029 return (offset + BPDT_HEADER_SIZE);
1031 /* Read all entries */
1032 assert((offset + get_bpdt_size(&bpdt->h)) < size);
1033 bpdt_read_entries((uint8_t *)data + offset + BPDT_HEADER_SIZE, bpdt,
1036 /* Read all sub-partition content in subpart_buf */
1037 return read_subpart_buf(data, size, &bpdt->e[0],
1038 bpdt->h.descriptor_count);
1041 static void parse_sbpdt(void *data, size_t size)
1043 struct bpdt_entry *s;
1045 s = find_entry_by_type(S_BPDT_TYPE);
1049 assert(size > s->offset);
1051 alloc_bpdt_buffer(data, size, s->offset,
1052 &ifwi_image.subpart_buf[S_BPDT_TYPE],
1056 static uint8_t calc_checksum(struct subpart_dir *s)
1058 size_t size = subpart_dir_size(&s->h);
1059 uint8_t *data = (uint8_t *)s;
1060 uint8_t checksum = 0;
1062 uint8_t old_checksum = s->h.checksum;
1066 for (i = 0; i < size; i++)
1067 checksum += data[i];
1069 s->h.checksum = old_checksum;
1075 static void validate_subpart_dir(struct subpart_dir *s, const char *name,
1076 bool checksum_check)
1078 if (s->h.marker != SUBPART_DIR_MARKER ||
1079 s->h.header_version != SUBPART_DIR_HEADER_VERSION_SUPPORTED ||
1080 s->h.entry_version != SUBPART_DIR_ENTRY_VERSION_SUPPORTED ||
1081 s->h.header_length != SUBPART_DIR_HEADER_SIZE) {
1082 ERROR("Invalid subpart_dir for %s.\n", name);
1086 if (!checksum_check)
1089 uint8_t checksum = calc_checksum(s);
1091 if (checksum != s->h.checksum)
1092 ERROR("Invalid checksum for %s (Expected=0x%x, Actual=0x%x).\n",
1093 name, checksum, s->h.checksum);
1096 static void validate_subpart_dir_without_checksum(struct subpart_dir *s,
1099 validate_subpart_dir(s, name, 0);
1102 static void validate_subpart_dir_with_checksum(struct subpart_dir *s,
1105 validate_subpart_dir(s, name, 1);
1108 static void parse_subpart_dir(struct buffer *subpart_dir_buf,
1109 struct buffer *input_buf, const char *name)
1111 struct subpart_dir_header hdr;
1113 uint8_t *data = buffer_get(input_buf);
1114 size_t size = buffer_size(input_buf);
1116 /* Read Subpart_Dir header */
1117 assert(size >= SUBPART_DIR_HEADER_SIZE);
1118 offset = read_member(data, offset, sizeof(hdr.marker), &hdr.marker);
1119 offset = read_member(data, offset, sizeof(hdr.num_entries),
1121 offset = read_member(data, offset, sizeof(hdr.header_version),
1122 &hdr.header_version);
1123 offset = read_member(data, offset, sizeof(hdr.entry_version),
1124 &hdr.entry_version);
1125 offset = read_member(data, offset, sizeof(hdr.header_length),
1126 &hdr.header_length);
1127 offset = read_member(data, offset, sizeof(hdr.checksum), &hdr.checksum);
1128 memcpy(hdr.name, data + offset, sizeof(hdr.name));
1129 offset += sizeof(hdr.name);
1131 validate_subpart_dir_without_checksum((struct subpart_dir *)&hdr, name);
1133 assert(size > subpart_dir_size(&hdr));
1134 alloc_buffer(subpart_dir_buf, subpart_dir_size(&hdr), "Subpart Dir");
1135 memcpy(buffer_get(subpart_dir_buf), &hdr, SUBPART_DIR_HEADER_SIZE);
1137 /* Read Subpart Dir entries */
1138 struct subpart_dir *subpart_dir = buffer_get(subpart_dir_buf);
1139 struct subpart_dir_entry *e = &subpart_dir->e[0];
1142 for (i = 0; i < hdr.num_entries; i++) {
1143 memcpy(e[i].name, data + offset, sizeof(e[i].name));
1144 offset += sizeof(e[i].name);
1145 offset = read_member(data, offset, sizeof(e[i].offset),
1147 offset = read_member(data, offset, sizeof(e[i].length),
1149 offset = read_member(data, offset, sizeof(e[i].rsvd),
1153 validate_subpart_dir_with_checksum(subpart_dir, name);
1155 print_subpart_dir(subpart_dir);
1158 /* Parse input image file to identify different sub-partitions */
1159 static int ifwi_parse(void)
1161 struct buffer *buff = &ifwi_image.input_buff;
1162 const char *image_name = param.image_name;
1164 DEBUG("Parsing IFWI image...\n");
1166 /* Read input file */
1167 if (buffer_from_file(buff, image_name)) {
1168 ERROR("Failed to read input file %s.\n", image_name);
1172 INFO("Buffer %p size 0x%zx\n", buff->data, buff->size);
1174 /* Look for BPDT signature at 4K intervals */
1176 void *data = buffer_get(buff);
1178 while (offset < buffer_size(buff)) {
1179 if (read_at_le32(data, offset) == BPDT_SIGNATURE)
1184 if (offset >= buffer_size(buff)) {
1185 ERROR("Image does not contain BPDT!!\n");
1189 ifwi_image.input_ifwi_start_offset = offset;
1190 INFO("BPDT starts at offset 0x%zx.\n", offset);
1192 data = (uint8_t *)data + offset;
1193 size_t ifwi_size = buffer_size(buff) - offset;
1195 /* Read BPDT and sub-partitions */
1196 uintptr_t end_offset;
1198 end_offset = ifwi_image.input_ifwi_start_offset +
1199 alloc_bpdt_buffer(data, ifwi_size, 0, &ifwi_image.bpdt, "BPDT");
1201 /* Parse S-BPDT, if any */
1202 parse_sbpdt(data, ifwi_size);
1205 * Store end offset of IFWI. Required for copying any trailing non-IFWI
1206 * part of the image.
1207 * ASSUMPTION: IFWI image always ends on a 4K boundary.
1209 ifwi_image.input_ifwi_end_offset = ALIGN(end_offset, 4 * KiB);
1210 DEBUG("Parsing done.\n");
1216 * This function is used by repack to count the number of BPDT and S-BPDT
1217 * entries that are present. It frees the current buffers used by the entries
1218 * and allocates fresh buffers that can be used for repacking. Returns BPDT
1219 * entries which are empty and need to be filled in.
1221 static void __bpdt_reset(struct buffer *b, size_t count, size_t size)
1223 size_t bpdt_size = BPDT_HEADER_SIZE + count * BPDT_ENTRY_SIZE;
1225 assert(size >= bpdt_size);
1228 * If buffer does not have the required size, allocate a fresh buffer.
1230 if (buffer_size(b) != size) {
1233 alloc_buffer(&temp, size, b->name);
1234 memcpy(buffer_get(&temp), buffer_get(b), buffer_size(b));
1239 struct bpdt *bpdt = buffer_get(b);
1240 uint8_t *ptr = (uint8_t *)&bpdt->e[0];
1241 size_t entries_size = BPDT_ENTRY_SIZE * count;
1243 /* Zero out BPDT entries */
1244 memset(ptr, 0, entries_size);
1245 /* Fill any pad-space with FF */
1246 memset(ptr + entries_size, 0xFF, size - bpdt_size);
1248 bpdt->h.descriptor_count = count;
1251 static void bpdt_reset(void)
1254 size_t bpdt_count = 0, sbpdt_count = 0, dummy_bpdt_count = 0;
1256 /* Count number of BPDT and S-BPDT entries */
1257 for (i = 0; i < MAX_SUBPARTS; i++) {
1258 if (buffer_size(&ifwi_image.subpart_buf[i]) == 0) {
1259 if (subparts[i].attr & MANDATORY_BPDT_ENTRY) {
1266 if (subparts[i].attr & NON_CRITICAL_SUBPART)
1272 DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count,
1273 dummy_bpdt_count, sbpdt_count);
1275 /* Update BPDT if required */
1276 size_t bpdt_size = max(BPDT_MIN_SIZE,
1277 BPDT_HEADER_SIZE + bpdt_count * BPDT_ENTRY_SIZE);
1278 __bpdt_reset(&ifwi_image.bpdt, bpdt_count, bpdt_size);
1280 /* Update S-BPDT if required */
1281 bpdt_size = ALIGN(BPDT_HEADER_SIZE + sbpdt_count * BPDT_ENTRY_SIZE,
1283 __bpdt_reset(&ifwi_image.subpart_buf[S_BPDT_TYPE], sbpdt_count,
1287 /* Initialize BPDT entries in header order */
1288 static void bpdt_entries_init_header_order(void)
1293 struct bpdt *bpdt, *sbpdt, *curr;
1294 size_t bpdt_curr = 0, sbpdt_curr = 0, *count_ptr;
1296 bpdt = buffer_get(&ifwi_image.bpdt);
1297 sbpdt = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1299 for (i = 0; i < MAX_SUBPARTS; i++) {
1300 type = bpdt_header_order[i];
1301 size = buffer_size(&ifwi_image.subpart_buf[type]);
1303 if (size == 0 && !(subparts[type].attr & MANDATORY_BPDT_ENTRY))
1306 if (subparts[type].attr & NON_CRITICAL_SUBPART) {
1308 count_ptr = &sbpdt_curr;
1311 count_ptr = &bpdt_curr;
1314 assert(*count_ptr < curr->h.descriptor_count);
1315 curr->e[*count_ptr].type = type;
1316 curr->e[*count_ptr].flags = 0;
1317 curr->e[*count_ptr].offset = 0;
1318 curr->e[*count_ptr].size = size;
1324 static void pad_buffer(struct buffer *b, size_t size)
1326 size_t buff_size = buffer_size(b);
1328 assert(buff_size <= size);
1330 if (buff_size == size)
1335 alloc_buffer(&temp, size, b->name);
1336 uint8_t *data = buffer_get(&temp);
1338 memcpy(data, buffer_get(b), buff_size);
1339 memset(data + buff_size, 0xFF, size - buff_size);
1344 /* Initialize offsets of entries using pack order */
1345 static void bpdt_entries_init_pack_order(void)
1348 struct bpdt_entry *curr;
1349 size_t curr_offset, curr_end;
1351 curr_offset = max(BPDT_MIN_SIZE, buffer_size(&ifwi_image.bpdt));
1354 * There are two types of sub-partitions that need to be handled here:
1355 * 1. Sub-partitions that lie within the same 4K as BPDT
1356 * 2. Sub-partitions that lie outside the 4K of BPDT
1358 * For sub-partitions of type # 1, there is no requirement on the start
1359 * or end of the sub-partition. They need to be packed in without any
1360 * holes left in between. If there is any empty space left after the end
1361 * of the last sub-partition in 4K of BPDT, then that space needs to be
1362 * padded with FF bytes, but the size of the last sub-partition remains
1365 * For sub-partitions of type # 2, both the start and end should be a
1366 * multiple of 4K. If not, then it needs to be padded with FF bytes and
1367 * size adjusted such that the sub-partition ends on 4K boundary.
1370 /* #1 Sub-partitions that lie within same 4K as BPDT */
1371 struct buffer *last_bpdt_buff = &ifwi_image.bpdt;
1373 for (i = 0; i < MAX_SUBPARTS; i++) {
1374 type = bpdt_pack_order[i];
1375 curr = find_entry_by_type(type);
1377 if (!curr || curr->size == 0)
1380 if (!(subparts[type].attr & LIES_WITHIN_BPDT_4K))
1383 curr->offset = curr_offset;
1384 curr_offset = curr->offset + curr->size;
1385 last_bpdt_buff = &ifwi_image.subpart_buf[type];
1386 DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
1387 type, curr_offset, curr->offset, curr->size,
1388 buffer_size(&ifwi_image.subpart_buf[type]));
1391 /* Pad ff bytes if there is any empty space left in BPDT 4K */
1392 curr_end = ALIGN(curr_offset, 4 * KiB);
1393 pad_buffer(last_bpdt_buff,
1394 buffer_size(last_bpdt_buff) + (curr_end - curr_offset));
1395 curr_offset = curr_end;
1397 /* #2 Sub-partitions that lie outside of BPDT 4K */
1398 for (i = 0; i < MAX_SUBPARTS; i++) {
1399 type = bpdt_pack_order[i];
1400 curr = find_entry_by_type(type);
1402 if (!curr || curr->size == 0)
1405 if (subparts[type].attr & LIES_WITHIN_BPDT_4K)
1408 assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1409 curr->offset = curr_offset;
1410 curr_end = ALIGN(curr->offset + curr->size, 4 * KiB);
1411 curr->size = curr_end - curr->offset;
1413 pad_buffer(&ifwi_image.subpart_buf[type], curr->size);
1415 curr_offset = curr_end;
1416 DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
1417 type, curr_offset, curr->offset, curr->size,
1418 buffer_size(&ifwi_image.subpart_buf[type]));
1422 * Update size of S-BPDT to include size of all non-critical
1425 * Assumption: S-BPDT always lies at the end of IFWI image.
1427 curr = find_entry_by_type(S_BPDT_TYPE);
1430 assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1431 curr->size = curr_offset - curr->offset;
1434 /* Convert all members of BPDT to little-endian format */
1435 static void bpdt_fixup_write_buffer(struct buffer *buf)
1437 struct bpdt *s = buffer_get(buf);
1439 struct bpdt_header *h = &s->h;
1440 struct bpdt_entry *e = &s->e[0];
1442 size_t count = h->descriptor_count;
1446 offset = fix_member(&h->signature, offset, sizeof(h->signature));
1447 offset = fix_member(&h->descriptor_count, offset,
1448 sizeof(h->descriptor_count));
1449 offset = fix_member(&h->bpdt_version, offset, sizeof(h->bpdt_version));
1450 offset = fix_member(&h->xor_redundant_block, offset,
1451 sizeof(h->xor_redundant_block));
1452 offset = fix_member(&h->ifwi_version, offset, sizeof(h->ifwi_version));
1453 offset = fix_member(&h->fit_tool_version, offset,
1454 sizeof(h->fit_tool_version));
1458 for (i = 0; i < count; i++) {
1459 offset = fix_member(&e[i].type, offset, sizeof(e[i].type));
1460 offset = fix_member(&e[i].flags, offset, sizeof(e[i].flags));
1461 offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
1462 offset = fix_member(&e[i].size, offset, sizeof(e[i].size));
1466 /* Write BPDT to output buffer after fixup */
1467 static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src)
1469 bpdt_fixup_write_buffer(src);
1470 memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src));
1474 * Follows these steps to re-create image:
1475 * 1. Write any non-IFWI prefix.
1476 * 2. Write out BPDT header and entries.
1477 * 3. Write sub-partition buffers to respective offsets.
1478 * 4. Write any non-IFWI suffix.
1480 * While performing the above steps, make sure that any empty holes are filled
1483 static void ifwi_write(const char *image_name)
1485 struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE);
1489 size_t ifwi_start, ifwi_end, file_end;
1491 ifwi_start = ifwi_image.input_ifwi_start_offset;
1492 ifwi_end = ifwi_start + ALIGN(s->offset + s->size, 4 * KiB);
1493 file_end = ifwi_end + (buffer_size(&ifwi_image.input_buff) -
1494 ifwi_image.input_ifwi_end_offset);
1498 alloc_buffer(&b, file_end, "Final-IFWI");
1500 uint8_t *input_data = buffer_get(&ifwi_image.input_buff);
1501 uint8_t *output_data = buffer_get(&b);
1503 DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start,
1504 ifwi_end, file_end);
1506 /* Copy non-IFWI prefix, if any */
1507 memcpy(output_data, input_data, ifwi_start);
1509 DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start);
1513 buffer_splice(&ifwi, &b, ifwi_start, ifwi_end - ifwi_start);
1514 uint8_t *ifwi_data = buffer_get(&ifwi);
1516 /* Copy sub-partitions using pack_order */
1517 struct bpdt_entry *curr;
1518 struct buffer *subpart_buf;
1521 for (i = 0; i < MAX_SUBPARTS; i++) {
1522 type = bpdt_pack_order[i];
1524 if (type == S_BPDT_TYPE)
1527 curr = find_entry_by_type(type);
1529 if (!curr || !curr->size)
1532 subpart_buf = &ifwi_image.subpart_buf[type];
1534 DEBUG("curr->offset=0x%x, curr->size=0x%x, type=%d, write_size=0x%zx\n",
1535 curr->offset, curr->size, type, buffer_size(subpart_buf));
1537 assert((curr->offset + buffer_size(subpart_buf)) <=
1538 buffer_size(&ifwi));
1540 memcpy(ifwi_data + curr->offset, buffer_get(subpart_buf),
1541 buffer_size(subpart_buf));
1544 /* Copy non-IFWI suffix, if any */
1545 if (ifwi_end != file_end) {
1546 memcpy(output_data + ifwi_end,
1547 input_data + ifwi_image.input_ifwi_end_offset,
1548 file_end - ifwi_end);
1549 DEBUG("Copied non-IFWI suffix (offset=0x%zx,size=0x%zx).\n",
1550 ifwi_end, file_end - ifwi_end);
1554 * Convert BPDT to little-endian format and write it to output buffer.
1555 * S-BPDT is written first and then BPDT.
1557 bpdt_write(&ifwi, s->offset, &ifwi_image.subpart_buf[S_BPDT_TYPE]);
1558 bpdt_write(&ifwi, 0, &ifwi_image.bpdt);
1560 if (buffer_write_file(&b, image_name)) {
1561 ERROR("File write error\n");
1566 printf("Image written successfully to %s.\n", image_name);
1570 * Calculate size and offset of each sub-partition again since it might have
1571 * changed because of add/delete operation. Also, re-create BPDT and S-BPDT
1572 * entries and write back the new IFWI image to file.
1574 static void ifwi_repack(void)
1577 bpdt_entries_init_header_order();
1578 bpdt_entries_init_pack_order();
1580 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1582 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1584 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1585 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1587 DEBUG("Repack done.. writing image.\n");
1588 ifwi_write(param.image_name);
1591 static void init_subpart_dir_header(struct subpart_dir_header *hdr,
1592 size_t count, const char *name)
1594 memset(hdr, 0, sizeof(*hdr));
1596 hdr->marker = SUBPART_DIR_MARKER;
1597 hdr->num_entries = count;
1598 hdr->header_version = SUBPART_DIR_HEADER_VERSION_SUPPORTED;
1599 hdr->entry_version = SUBPART_DIR_ENTRY_VERSION_SUPPORTED;
1600 hdr->header_length = SUBPART_DIR_HEADER_SIZE;
1601 memcpy(hdr->name, name, sizeof(hdr->name));
1604 static size_t init_subpart_dir_entry(struct subpart_dir_entry *e,
1605 struct buffer *b, size_t offset)
1607 memset(e, 0, sizeof(*e));
1609 assert(strlen(b->name) <= sizeof(e->name));
1610 strncpy((char *)e->name, (char *)b->name, sizeof(e->name));
1612 e->length = buffer_size(b);
1614 return (offset + buffer_size(b));
1617 static void init_manifest_header(struct manifest_header *hdr, size_t size)
1619 memset(hdr, 0, sizeof(*hdr));
1621 hdr->header_type = 0x4;
1622 assert((MANIFEST_HDR_SIZE % DWORD_SIZE) == 0);
1623 hdr->header_length = MANIFEST_HDR_SIZE / DWORD_SIZE;
1624 hdr->header_version = 0x10000;
1625 hdr->vendor = 0x8086;
1627 struct tm *local_time;
1631 curr_time = time(NULL);
1632 local_time = localtime(&curr_time);
1633 strftime(buffer, sizeof(buffer), "0x%Y%m%d", local_time);
1634 hdr->date = strtoul(buffer, NULL, 16);
1636 assert((size % DWORD_SIZE) == 0);
1637 hdr->size = size / DWORD_SIZE;
1638 hdr->id = MANIFEST_ID_MAGIC;
1641 static void init_signed_pkg_info_ext(struct signed_pkg_info_ext *ext,
1642 size_t count, const char *name)
1644 memset(ext, 0, sizeof(*ext));
1646 ext->ext_type = SIGNED_PKG_INFO_EXT_TYPE;
1647 ext->ext_length = SIGNED_PKG_INFO_EXT_SIZE + count * MODULE_SIZE;
1648 memcpy(ext->name, name, sizeof(ext->name));
1651 static void subpart_dir_fixup_write_buffer(struct buffer *buf)
1653 struct subpart_dir *s = buffer_get(buf);
1654 struct subpart_dir_header *h = &s->h;
1655 struct subpart_dir_entry *e = &s->e[0];
1657 size_t count = h->num_entries;
1660 offset = fix_member(&h->marker, offset, sizeof(h->marker));
1661 offset = fix_member(&h->num_entries, offset, sizeof(h->num_entries));
1662 offset = fix_member(&h->header_version, offset,
1663 sizeof(h->header_version));
1664 offset = fix_member(&h->entry_version, offset,
1665 sizeof(h->entry_version));
1666 offset = fix_member(&h->header_length, offset,
1667 sizeof(h->header_length));
1668 offset = fix_member(&h->checksum, offset, sizeof(h->checksum));
1669 offset += sizeof(h->name);
1673 for (i = 0; i < count; i++) {
1674 offset += sizeof(e[i].name);
1675 offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
1676 offset = fix_member(&e[i].length, offset, sizeof(e[i].length));
1677 offset = fix_member(&e[i].rsvd, offset, sizeof(e[i].rsvd));
1681 static void create_subpart(struct buffer *dst, struct buffer *info[],
1682 size_t count, const char *name)
1684 struct buffer subpart_dir_buff;
1685 size_t size = SUBPART_DIR_HEADER_SIZE + count * SUBPART_DIR_ENTRY_SIZE;
1687 alloc_buffer(&subpart_dir_buff, size, "subpart-dir");
1689 struct subpart_dir_header *h = buffer_get(&subpart_dir_buff);
1690 struct subpart_dir_entry *e = (struct subpart_dir_entry *)(h + 1);
1692 init_subpart_dir_header(h, count, name);
1694 size_t curr_offset = size;
1697 for (i = 0; i < count; i++) {
1698 curr_offset = init_subpart_dir_entry(&e[i], info[i],
1702 alloc_buffer(dst, curr_offset, name);
1703 uint8_t *data = buffer_get(dst);
1705 for (i = 0; i < count; i++) {
1706 memcpy(data + e[i].offset, buffer_get(info[i]),
1707 buffer_size(info[i]));
1710 h->checksum = calc_checksum(buffer_get(&subpart_dir_buff));
1712 struct subpart_dir *dir = buffer_get(&subpart_dir_buff);
1714 print_subpart_dir(dir);
1716 subpart_dir_fixup_write_buffer(&subpart_dir_buff);
1717 memcpy(data, dir, buffer_size(&subpart_dir_buff));
1719 buffer_delete(&subpart_dir_buff);
1722 static enum ifwi_ret ibbp_dir_add(int type)
1724 struct buffer manifest;
1725 struct signed_pkg_info_ext *ext;
1729 #define DUMMY_IBB_SIZE (4 * KiB)
1731 assert(type == IBB_TYPE);
1734 * Entry # 1 - IBBP.man
1735 * Contains manifest header and signed pkg info extension.
1737 size_t size = MANIFEST_HDR_SIZE + SIGNED_PKG_INFO_EXT_SIZE;
1739 alloc_buffer(&manifest, size, "IBBP.man");
1741 struct manifest_header *man_hdr = buffer_get(&manifest);
1743 init_manifest_header(man_hdr, size);
1745 ext = (struct signed_pkg_info_ext *)(man_hdr + 1);
1747 init_signed_pkg_info_ext(ext, 0, subparts[type].name);
1749 /* Entry # 2 - IBBL */
1750 if (buffer_from_file(&ibbl, param.file_name))
1753 /* Entry # 3 - IBB */
1754 alloc_buffer(&ibb, DUMMY_IBB_SIZE, "IBB");
1755 memset(buffer_get(&ibb), 0xFF, DUMMY_IBB_SIZE);
1757 /* Create subpartition */
1758 struct buffer *info[] = {
1759 &manifest, &ibbl, &ibb,
1761 create_subpart(&ifwi_image.subpart_buf[type], &info[0],
1762 ARRAY_SIZE(info), subparts[type].name);
1764 return REPACK_REQUIRED;
1767 static enum ifwi_ret ifwi_raw_add(int type)
1769 if (buffer_from_file(&ifwi_image.subpart_buf[type], param.file_name))
1772 printf("Sub-partition %s(%d) added from file %s.\n", param.subpart_name,
1773 type, param.file_name);
1774 return REPACK_REQUIRED;
1777 static enum ifwi_ret ifwi_dir_add(int type)
1779 if (!(subparts[type].attr & CONTAINS_DIR) ||
1780 !subparts[type].dir_ops.dir_add) {
1781 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1782 subparts[type].name, type);
1786 if (!param.dentry_name) {
1787 ERROR("%s: -e option required\n", __func__);
1791 enum ifwi_ret ret = subparts[type].dir_ops.dir_add(type);
1793 if (ret != COMMAND_ERR)
1794 printf("Sub-partition %s(%d) entry %s added from file %s.\n",
1795 param.subpart_name, type, param.dentry_name,
1798 ERROR("Sub-partition dir operation failed.\n");
1803 static enum ifwi_ret ifwi_add(void)
1805 if (!param.file_name) {
1806 ERROR("%s: -f option required\n", __func__);
1810 if (!param.subpart_name) {
1811 ERROR("%s: -n option required\n", __func__);
1815 int type = find_type_by_name(param.subpart_name);
1820 const struct subpart_info *curr_subpart = &subparts[type];
1822 if (curr_subpart->attr & AUTO_GENERATED) {
1823 ERROR("Cannot add auto-generated sub-partitions.\n");
1827 if (buffer_size(&ifwi_image.subpart_buf[type])) {
1828 ERROR("Image already contains sub-partition %s(%d).\n",
1829 param.subpart_name, type);
1834 return ifwi_dir_add(type);
1836 return ifwi_raw_add(type);
1839 static enum ifwi_ret ifwi_delete(void)
1841 if (!param.subpart_name) {
1842 ERROR("%s: -n option required\n", __func__);
1846 int type = find_type_by_name(param.subpart_name);
1851 const struct subpart_info *curr_subpart = &subparts[type];
1853 if (curr_subpart->attr & AUTO_GENERATED) {
1854 ERROR("Cannot delete auto-generated sub-partitions.\n");
1858 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1859 printf("Image does not contain sub-partition %s(%d).\n",
1860 param.subpart_name, type);
1861 return NO_ACTION_REQUIRED;
1864 buffer_delete(&ifwi_image.subpart_buf[type]);
1865 printf("Sub-Partition %s(%d) deleted.\n", subparts[type].name, type);
1866 return REPACK_REQUIRED;
1869 static enum ifwi_ret ifwi_dir_extract(int type)
1871 if (!(subparts[type].attr & CONTAINS_DIR)) {
1872 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1873 subparts[type].name, type);
1877 if (!param.dentry_name) {
1878 ERROR("%s: -e option required.\n", __func__);
1882 struct buffer subpart_dir_buff;
1884 parse_subpart_dir(&subpart_dir_buff, &ifwi_image.subpart_buf[type],
1885 subparts[type].name);
1888 struct subpart_dir *s = buffer_get(&subpart_dir_buff);
1890 for (i = 0; i < s->h.num_entries; i++) {
1891 if (!strncmp((char *)s->e[i].name, param.dentry_name,
1892 sizeof(s->e[i].name)))
1896 if (i == s->h.num_entries) {
1897 ERROR("Entry %s not found in subpartition for %s.\n",
1898 param.dentry_name, param.subpart_name);
1904 DEBUG("Splicing buffer at 0x%x size 0x%x\n", s->e[i].offset,
1906 buffer_splice(&dst, &ifwi_image.subpart_buf[type], s->e[i].offset,
1909 if (buffer_write_file(&dst, param.file_name))
1912 printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1913 param.subpart_name, type, param.dentry_name, param.file_name);
1915 return NO_ACTION_REQUIRED;
1918 static enum ifwi_ret ifwi_raw_extract(int type)
1920 if (buffer_write_file(&ifwi_image.subpart_buf[type], param.file_name))
1923 printf("Sub-Partition %s(%d) stored in %s.\n", param.subpart_name, type,
1926 return NO_ACTION_REQUIRED;
1929 static enum ifwi_ret ifwi_extract(void)
1931 if (!param.file_name) {
1932 ERROR("%s: -f option required\n", __func__);
1936 if (!param.subpart_name) {
1937 ERROR("%s: -n option required\n", __func__);
1941 int type = find_type_by_name(param.subpart_name);
1946 if (type == S_BPDT_TYPE) {
1947 INFO("Tool does not support raw extract for %s\n",
1948 param.subpart_name);
1949 return NO_ACTION_REQUIRED;
1952 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1953 ERROR("Image does not contain sub-partition %s(%d).\n",
1954 param.subpart_name, type);
1958 INFO("Extracting sub-partition %s(%d).\n", param.subpart_name, type);
1960 return ifwi_dir_extract(type);
1962 return ifwi_raw_extract(type);
1965 static enum ifwi_ret ifwi_print(void)
1969 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1971 bpdt_print_header(&b->h, "BPDT");
1972 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1974 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1975 bpdt_print_header(&b->h, "S-BPDT");
1976 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1978 if (param.dir_ops == 0) {
1980 return NO_ACTION_REQUIRED;
1984 struct buffer subpart_dir_buf;
1986 for (i = 0; i < MAX_SUBPARTS ; i++) {
1987 if (!(subparts[i].attr & CONTAINS_DIR) ||
1988 (buffer_size(&ifwi_image.subpart_buf[i]) == 0))
1991 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[i],
1993 buffer_delete(&subpart_dir_buf);
1998 return NO_ACTION_REQUIRED;
2001 static enum ifwi_ret ifwi_raw_replace(int type)
2003 buffer_delete(&ifwi_image.subpart_buf[type]);
2004 return ifwi_raw_add(type);
2007 static enum ifwi_ret ifwi_dir_replace(int type)
2009 if (!(subparts[type].attr & CONTAINS_DIR)) {
2010 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
2011 subparts[type].name, type);
2015 if (!param.dentry_name) {
2016 ERROR("%s: -e option required.\n", __func__);
2020 struct buffer subpart_dir_buf;
2022 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[type],
2023 subparts[type].name);
2026 struct subpart_dir *s = buffer_get(&subpart_dir_buf);
2028 for (i = 0; i < s->h.num_entries; i++) {
2029 if (!strcmp((char *)s->e[i].name, param.dentry_name))
2033 if (i == s->h.num_entries) {
2034 ERROR("Entry %s not found in subpartition for %s.\n",
2035 param.dentry_name, param.subpart_name);
2041 if (buffer_from_file(&b, param.file_name)) {
2042 ERROR("Failed to read %s\n", param.file_name);
2047 size_t dst_size = buffer_size(&ifwi_image.subpart_buf[type]) +
2048 buffer_size(&b) - s->e[i].length;
2049 size_t subpart_start = s->e[i].offset;
2050 size_t subpart_end = s->e[i].offset + s->e[i].length;
2052 alloc_buffer(&dst, dst_size, ifwi_image.subpart_buf[type].name);
2054 uint8_t *src_data = buffer_get(&ifwi_image.subpart_buf[type]);
2055 uint8_t *dst_data = buffer_get(&dst);
2056 size_t curr_offset = 0;
2058 /* Copy data before the sub-partition entry */
2059 memcpy(dst_data + curr_offset, src_data, subpart_start);
2060 curr_offset += subpart_start;
2062 /* Copy sub-partition entry */
2063 memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
2064 curr_offset += buffer_size(&b);
2066 /* Copy remaining data */
2067 memcpy(dst_data + curr_offset, src_data + subpart_end,
2068 buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end);
2070 /* Update sub-partition buffer */
2071 int offset = s->e[i].offset;
2073 buffer_delete(&ifwi_image.subpart_buf[type]);
2074 ifwi_image.subpart_buf[type] = dst;
2076 /* Update length of entry in the subpartition */
2077 s->e[i].length = buffer_size(&b);
2080 /* Adjust offsets of affected entries in subpartition */
2081 offset = s->e[i].offset - offset;
2082 for (; i < s->h.num_entries; i++)
2083 s->e[i].offset += offset;
2085 /* Re-calculate checksum */
2086 s->h.checksum = calc_checksum(s);
2088 /* Convert members to litte-endian */
2089 subpart_dir_fixup_write_buffer(&subpart_dir_buf);
2091 memcpy(dst_data, buffer_get(&subpart_dir_buf),
2092 buffer_size(&subpart_dir_buf));
2094 buffer_delete(&subpart_dir_buf);
2096 printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
2097 param.subpart_name, type, param.dentry_name, param.file_name);
2099 return REPACK_REQUIRED;
2102 static enum ifwi_ret ifwi_replace(void)
2104 if (!param.file_name) {
2105 ERROR("%s: -f option required\n", __func__);
2109 if (!param.subpart_name) {
2110 ERROR("%s: -n option required\n", __func__);
2114 int type = find_type_by_name(param.subpart_name);
2119 const struct subpart_info *curr_subpart = &subparts[type];
2121 if (curr_subpart->attr & AUTO_GENERATED) {
2122 ERROR("Cannot replace auto-generated sub-partitions.\n");
2126 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
2127 ERROR("Image does not contain sub-partition %s(%d).\n",
2128 param.subpart_name, type);
2133 return ifwi_dir_replace(type);
2135 return ifwi_raw_replace(type);
2138 static enum ifwi_ret ifwi_create(void)
2141 * Create peels off any non-IFWI content present in the input buffer and
2142 * creates output file with only the IFWI present.
2145 if (!param.file_name) {
2146 ERROR("%s: -f option required\n", __func__);
2150 /* Peel off any non-IFWI prefix */
2151 buffer_seek(&ifwi_image.input_buff,
2152 ifwi_image.input_ifwi_start_offset);
2153 /* Peel off any non-IFWI suffix */
2154 buffer_set_size(&ifwi_image.input_buff,
2155 ifwi_image.input_ifwi_end_offset -
2156 ifwi_image.input_ifwi_start_offset);
2159 * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
2161 ifwi_image.input_ifwi_end_offset -= ifwi_image.input_ifwi_start_offset;
2162 ifwi_image.input_ifwi_start_offset = 0;
2164 param.image_name = param.file_name;
2166 return REPACK_REQUIRED;
2171 const char *optstring;
2172 enum ifwi_ret (*function)(void);
2175 static const struct command commands[] = {
2176 {"add", "f:n:e:dvh?", ifwi_add},
2177 {"create", "f:vh?", ifwi_create},
2178 {"delete", "f:n:vh?", ifwi_delete},
2179 {"extract", "f:n:e:dvh?", ifwi_extract},
2180 {"print", "dh?", ifwi_print},
2181 {"replace", "f:n:e:dvh?", ifwi_replace},
2184 static struct option long_options[] = {
2185 {"subpart_dentry", required_argument, 0, 'e'},
2186 {"file", required_argument, 0, 'f'},
2187 {"help", required_argument, 0, 'h'},
2188 {"name", required_argument, 0, 'n'},
2189 {"dir_ops", no_argument, 0, 'd'},
2190 {"verbose", no_argument, 0, 'v'},
2194 static void usage(const char *name)
2196 printf("ifwitool: Utility for IFWI manipulation\n\n"
2199 " %s FILE COMMAND [PARAMETERS]\n\n"
2201 " add -f FILE -n NAME [-d -e ENTRY]\n"
2204 " extract -f FILE -n NAME [-d -e ENTRY]\n"
2206 " replace -f FILE -n NAME [-d -e ENTRY]\n"
2208 " -f FILE : File to read/write/create/extract\n"
2209 " -d : Perform directory operation\n"
2210 " -e ENTRY: Name of directory entry to operate on\n"
2211 " -v : Verbose level\n"
2212 " -h : Help message\n"
2213 " -n NAME : Name of sub-partition to operate on\n",
2217 printf("\nNAME should be one of:\n");
2220 for (i = 0; i < MAX_SUBPARTS; i++)
2221 printf("%s(%s)\n", subparts[i].name, subparts[i].readable_name);
2225 int main(int argc, char **argv)
2232 param.image_name = argv[1];
2233 char *cmd = argv[2];
2239 for (i = 0; i < ARRAY_SIZE(commands); i++) {
2240 if (strcmp(cmd, commands[i].name) != 0)
2248 c = getopt_long(argc, argv, commands[i].optstring,
2249 long_options, &option_index);
2254 /* Filter out illegal long options */
2255 if (!strchr(commands[i].optstring, c)) {
2256 ERROR("%s: invalid option -- '%c'\n", argv[0],
2263 param.subpart_name = optarg;
2266 param.file_name = optarg;
2272 param.dentry_name = optarg;
2287 ERROR("%s: ifwi parsing failed\n", argv[0]);
2291 enum ifwi_ret ret = commands[i].function();
2293 if (ret == COMMAND_ERR) {
2294 ERROR("%s: failed execution\n", argv[0]);
2298 if (ret == REPACK_REQUIRED)
2304 ERROR("%s: invalid command\n", argv[0]);