Merge tag 'dm-pull-29oct19' of git://git.denx.de/u-boot-dm
[oweals/u-boot.git] / tools / ifwitool.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * ifwitool, CLI utility for Integrated Firmware Image (IFWI) manipulation
4  *
5  * This is taken from the Coreboot project
6  */
7
8 #include <assert.h>
9 #include <stdbool.h>
10 #include <getopt.h>
11 #include "os_support.h"
12
13 #ifndef __packed
14 #define __packed                __attribute__((packed))
15 #endif
16 #define KiB                     1024
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]))
20
21 /*
22  * min()/max()/clamp() macros that also do
23  * strict type-checking.. See the
24  * "unnecessary" pointer comparison.
25  */
26 #define min(x, y) ({                            \
27         typeof(x) _min1 = (x);                  \
28         typeof(y) _min2 = (y);                  \
29         (void)&_min1 == &_min2);                \
30         _min1 < _min2 ? _min1 : _min2; })
31
32 #define max(x, y) ({                            \
33         typeof(x) _max1 = (x);                  \
34         typeof(y) _max2 = (y);                  \
35         (void)(&_max1 == &_max2);               \
36         _max1 > _max2 ? _max1 : _max2; })
37
38 static int verbose = 1;
39
40 /* Buffer and file I/O */
41 struct buffer {
42         char *name;
43         char *data;
44         size_t offset;
45         size_t size;
46 };
47
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__); }
51
52 /*
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.
56  *
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.
60  *
61  * Both tables are identified by BPDT_SIGNATURE stored at the start of the
62  * table.
63  */
64 #define BPDT_SIGNATURE                          (0x000055AA)
65
66 /* Parameters passed in by caller */
67 static struct param {
68         const char *file_name;
69         const char *subpart_name;
70         const char *image_name;
71         bool dir_ops;
72         const char *dentry_name;
73 } param;
74
75 struct bpdt_header {
76         /*
77          * This is used to identify start of BPDT. It should always be
78          * BPDT_SIGNATURE.
79          */
80         uint32_t signature;
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;
91 } __packed;
92 #define BPDT_HEADER_SIZE                        (sizeof(struct bpdt_header))
93
94 struct bpdt_entry {
95         /* Type of sub-partition */
96         uint16_t type;
97         /* Attributes of sub-partition */
98         uint16_t flags;
99         /* Offset of sub-partition from beginning of LBP */
100         uint32_t offset;
101         /* Size in bytes of sub-partition */
102         uint32_t size;
103 } __packed;
104 #define BPDT_ENTRY_SIZE                 (sizeof(struct bpdt_entry))
105
106 struct bpdt {
107         struct bpdt_header h;
108         /* In practice, this could be an array of 0 to n entries */
109         struct bpdt_entry e[0];
110 } __packed;
111
112 static inline size_t get_bpdt_size(struct bpdt_header *h)
113 {
114         return (sizeof(*h) + BPDT_ENTRY_SIZE * h->descriptor_count);
115 }
116
117 /* Minimum size in bytes allocated to BPDT in IFWI */
118 #define BPDT_MIN_SIZE                   ((size_t)512)
119
120 /* Header to define directory header for sub-partition */
121 struct subpart_dir_header {
122         /* Should be SUBPART_DIR_MARKER */
123         uint32_t 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;
132         /*
133          * 2s complement of 8-bit sum from first byte of header to last byte of
134          * last directory entry.
135          */
136         uint8_t checksum;
137         /* ASCII short name of sub-partition */
138         uint8_t name[4];
139 } __packed;
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
145
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 */
149         uint8_t name[12];
150         /* Offset of entry from beginning of sub-partition */
151         uint32_t offset;
152         /* Length in bytes of sub-directory entry */
153         uint32_t length;
154         /* Must be zero */
155         uint32_t rsvd;
156 } __packed;
157 #define SUBPART_DIR_ENTRY_SIZE                  \
158                                         (sizeof(struct subpart_dir_entry))
159
160 struct subpart_dir {
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];
164 } __packed;
165
166 static inline size_t subpart_dir_size(struct subpart_dir_header *h)
167 {
168         return (sizeof(*h) + SUBPART_DIR_ENTRY_SIZE * h->num_entries);
169 }
170
171 struct manifest_header {
172         uint32_t header_type;
173         uint32_t header_length;
174         uint32_t header_version;
175         uint32_t flags;
176         uint32_t vendor;
177         uint32_t date;
178         uint32_t size;
179         uint32_t id;
180         uint32_t rsvd;
181         uint64_t version;
182         uint32_t svn;
183         uint64_t rsvd1;
184         uint8_t rsvd2[64];
185         uint32_t modulus_size;
186         uint32_t exponent_size;
187         uint8_t public_key[256];
188         uint32_t exponent;
189         uint8_t signature[256];
190 } __packed;
191
192 #define DWORD_SIZE                              4
193 #define MANIFEST_HDR_SIZE                       (sizeof(struct manifest_header))
194 #define MANIFEST_ID_MAGIC                       (0x324e4d24)
195
196 struct module {
197         uint8_t name[12];
198         uint8_t type;
199         uint8_t hash_alg;
200         uint16_t hash_size;
201         uint32_t metadata_size;
202         uint8_t metadata_hash[32];
203 } __packed;
204
205 #define MODULE_SIZE                             (sizeof(struct module))
206
207 struct signed_pkg_info_ext {
208         uint32_t ext_type;
209         uint32_t ext_length;
210         uint8_t name[4];
211         uint32_t vcn;
212         uint8_t bitmap[16];
213         uint32_t svn;
214         uint8_t rsvd[16];
215 } __packed;
216
217 #define SIGNED_PKG_INFO_EXT_TYPE                0x15
218 #define SIGNED_PKG_INFO_EXT_SIZE                \
219         (sizeof(struct signed_pkg_info_ext))
220
221 /*
222  * Attributes for various IFWI sub-partitions.
223  * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
224  * BPDT.
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.
230  */
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),
237 };
238
239 /* Type value for various IFWI sub-partitions */
240 enum bpdt_entry_type {
241         SMIP_TYPE               = 0,
242         CSE_RBE_TYPE            = 1,
243         CSE_BUP_TYPE            = 2,
244         UCODE_TYPE              = 3,
245         IBB_TYPE                = 4,
246         S_BPDT_TYPE             = 5,
247         OBB_TYPE                = 6,
248         CSE_MAIN_TYPE           = 7,
249         ISH_TYPE                = 8,
250         CSE_IDLM_TYPE           = 9,
251         IFP_OVERRIDE_TYPE       = 10,
252         DEBUG_TOKENS_TYPE       = 11,
253         UFS_PHY_TYPE            = 12,
254         UFS_GPP_TYPE            = 13,
255         PMC_TYPE                = 14,
256         IUNIT_TYPE              = 15,
257         NVM_CONFIG_TYPE = 16,
258         UEP_TYPE                = 17,
259         UFS_RATE_B_TYPE = 18,
260         MAX_SUBPARTS            = 19,
261 };
262
263 /*
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.
267  *
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.
272  */
273 const enum bpdt_entry_type bpdt_header_order[MAX_SUBPARTS] = {
274         /* Order of the following entries is mandatory */
275         CSE_IDLM_TYPE,
276         IFP_OVERRIDE_TYPE,
277         S_BPDT_TYPE,
278         CSE_RBE_TYPE,
279         UFS_PHY_TYPE,
280         UFS_GPP_TYPE,
281         /* Order of the following entries is recommended */
282         UEP_TYPE,
283         NVM_CONFIG_TYPE,
284         UFS_RATE_B_TYPE,
285         IBB_TYPE,
286         SMIP_TYPE,
287         PMC_TYPE,
288         CSE_BUP_TYPE,
289         UCODE_TYPE,
290         DEBUG_TOKENS_TYPE,
291         IUNIT_TYPE,
292         CSE_MAIN_TYPE,
293         ISH_TYPE,
294         OBB_TYPE,
295 };
296
297 const enum bpdt_entry_type bpdt_pack_order[MAX_SUBPARTS] = {
298         /* Order of the following entries is mandatory */
299         UFS_GPP_TYPE,
300         UFS_PHY_TYPE,
301         IFP_OVERRIDE_TYPE,
302         UEP_TYPE,
303         NVM_CONFIG_TYPE,
304         UFS_RATE_B_TYPE,
305         /* Order of the following entries is recommended */
306         IBB_TYPE,
307         SMIP_TYPE,
308         CSE_RBE_TYPE,
309         PMC_TYPE,
310         CSE_BUP_TYPE,
311         UCODE_TYPE,
312         CSE_IDLM_TYPE,
313         DEBUG_TOKENS_TYPE,
314         S_BPDT_TYPE,
315         IUNIT_TYPE,
316         CSE_MAIN_TYPE,
317         ISH_TYPE,
318         OBB_TYPE,
319 };
320
321 /* Utility functions */
322 enum ifwi_ret {
323         COMMAND_ERR = -1,
324         NO_ACTION_REQUIRED = 0,
325         REPACK_REQUIRED = 1,
326 };
327
328 struct dir_ops {
329         enum ifwi_ret (*dir_add)(int type);
330 };
331
332 static enum ifwi_ret ibbp_dir_add(int type);
333
334 const struct subpart_info {
335         const char *name;
336         const char *readable_name;
337         uint32_t attr;
338         struct dir_ops dir_ops;
339 } subparts[MAX_SUBPARTS] = {
340         /* OEM SMIP */
341         [SMIP_TYPE] = {"SMIP", "SMIP", CONTAINS_DIR, {NULL} },
342         /* CSE RBE */
343         [CSE_RBE_TYPE] = {"RBEP", "CSE_RBE", CONTAINS_DIR |
344                           MANDATORY_BPDT_ENTRY, {NULL} },
345         /* CSE BUP */
346         [CSE_BUP_TYPE] = {"FTPR", "CSE_BUP", CONTAINS_DIR |
347                           MANDATORY_BPDT_ENTRY, {NULL} },
348         /* uCode */
349         [UCODE_TYPE] = {"UCOD", "Microcode", CONTAINS_DIR, {NULL} },
350         /* IBB */
351         [IBB_TYPE] = {"IBBP", "Bootblock", CONTAINS_DIR, {ibbp_dir_add} },
352         /* S-BPDT */
353         [S_BPDT_TYPE] = {"S_BPDT", "S-BPDT", AUTO_GENERATED |
354                          MANDATORY_BPDT_ENTRY, {NULL} },
355         /* OBB */
356         [OBB_TYPE] = {"OBBP", "OEM boot block", CONTAINS_DIR |
357                       NON_CRITICAL_SUBPART, {NULL} },
358         /* CSE Main */
359         [CSE_MAIN_TYPE] = {"NFTP", "CSE_MAIN", CONTAINS_DIR |
360                            NON_CRITICAL_SUBPART, {NULL} },
361         /* ISH */
362         [ISH_TYPE] = {"ISHP", "ISH", NON_CRITICAL_SUBPART, {NULL} },
363         /* CSE IDLM */
364         [CSE_IDLM_TYPE] = {"DLMP", "CSE_IDLM", CONTAINS_DIR |
365                            MANDATORY_BPDT_ENTRY, {NULL} },
366         /* IFP Override */
367         [IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
368                                LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
369                                {NULL} },
370         /* Debug Tokens */
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} },
375         /* UFS GPP LUN ID */
376         [UFS_GPP_TYPE] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K |
377                           MANDATORY_BPDT_ENTRY, {NULL} },
378         /* PMC */
379         [PMC_TYPE] = {"PMCP", "PMC firmware", CONTAINS_DIR, {NULL} },
380         /* IUNIT */
381         [IUNIT_TYPE] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART, {NULL} },
382         /* NVM Config */
383         [NVM_CONFIG_TYPE] = {"NVM_CONFIG", "NVM Config", 0, {NULL} },
384         /* UEP */
385         [UEP_TYPE] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
386                       {NULL} },
387         /* UFS Rate B Config */
388         [UFS_RATE_B_TYPE] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL} },
389 };
390
391 struct ifwi_image {
392         /* Data read from input file */
393         struct buffer input_buff;
394
395         /* BPDT header and entries */
396         struct buffer bpdt;
397         size_t input_ifwi_start_offset;
398         size_t input_ifwi_end_offset;
399
400         /* Subpartition content */
401         struct buffer subpart_buf[MAX_SUBPARTS];
402 } ifwi_image;
403
404 /* Buffer and file I/O */
405 static off_t get_file_size(FILE *f)
406 {
407         off_t fsize;
408
409         fseek(f, 0, SEEK_END);
410         fsize = ftell(f);
411         fseek(f, 0, SEEK_SET);
412         return fsize;
413 }
414
415 static inline void *buffer_get(const struct buffer *b)
416 {
417         return b->data;
418 }
419
420 static inline size_t buffer_size(const struct buffer *b)
421 {
422         return b->size;
423 }
424
425 static inline size_t buffer_offset(const struct buffer *b)
426 {
427         return b->offset;
428 }
429
430 /*
431  * Shrink a buffer toward the beginning of its previous space.
432  * Afterward, buffer_delete() remains the means of cleaning it up
433  */
434 static inline void buffer_set_size(struct buffer *b, size_t size)
435 {
436         b->size = size;
437 }
438
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
443  */
444 static void buffer_splice(struct buffer *dest, const struct buffer *src,
445                           size_t offset, size_t size)
446 {
447         dest->name = src->name;
448         dest->data = src->data + offset;
449         dest->offset = src->offset + offset;
450         dest->size = size;
451 }
452
453 /*
454  * Shrink a buffer toward the end of its previous space.
455  * Afterward, buffer_delete() remains the means of cleaning it up
456  */
457 static inline void buffer_seek(struct buffer *b, size_t size)
458 {
459         b->offset += size;
460         b->size -= size;
461         b->data += size;
462 }
463
464 /* Returns the start of the underlying buffer, with the offset undone */
465 static inline void *buffer_get_original_backing(const struct buffer *b)
466 {
467         if (!b)
468                 return NULL;
469         return buffer_get(b) - buffer_offset(b);
470 }
471
472 int buffer_create(struct buffer *buffer, size_t size, const char *name)
473 {
474         buffer->name = strdup(name);
475         buffer->offset = 0;
476         buffer->size = size;
477         buffer->data = (char *)malloc(buffer->size);
478         if (!buffer->data) {
479                 fprintf(stderr, "%s: Insufficient memory (0x%zx).\n", __func__,
480                         size);
481         }
482
483         return !buffer->data;
484 }
485
486 int buffer_write_file(struct buffer *buffer, const char *filename)
487 {
488         FILE *fp = fopen(filename, "wb");
489
490         if (!fp) {
491                 perror(filename);
492                 return -1;
493         }
494         assert(buffer && buffer->data);
495         if (fwrite(buffer->data, 1, buffer->size, fp) != buffer->size) {
496                 fprintf(stderr, "incomplete write: %s\n", filename);
497                 fclose(fp);
498                 return -1;
499         }
500         fclose(fp);
501         return 0;
502 }
503
504 void buffer_delete(struct buffer *buffer)
505 {
506         assert(buffer);
507         if (buffer->name) {
508                 free(buffer->name);
509                 buffer->name = NULL;
510         }
511         if (buffer->data) {
512                 free(buffer_get_original_backing(buffer));
513                 buffer->data = NULL;
514         }
515         buffer->offset = 0;
516         buffer->size = 0;
517 }
518
519 int buffer_from_file(struct buffer *buffer, const char *filename)
520 {
521         FILE *fp = fopen(filename, "rb");
522
523         if (!fp) {
524                 perror(filename);
525                 return -1;
526         }
527         buffer->offset = 0;
528         off_t file_size = get_file_size(fp);
529
530         if (file_size < 0) {
531                 fprintf(stderr, "could not determine size of %s\n", filename);
532                 fclose(fp);
533                 return -1;
534         }
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);
541                 fclose(fp);
542                 buffer_delete(buffer);
543                 return -1;
544         }
545         fclose(fp);
546         return 0;
547 }
548
549 static void alloc_buffer(struct buffer *b, size_t s, const char *n)
550 {
551         if (buffer_create(b, s, n) == 0)
552                 return;
553
554         ERROR("Buffer allocation failure for %s (size = %zx).\n", n, s);
555         exit(-1);
556 }
557
558 /* Little-Endian functions */
559 static inline uint8_t read_ble8(const void *src)
560 {
561         const uint8_t *s = src;
562         return *s;
563 }
564
565 static inline uint8_t read_at_ble8(const void *src, size_t offset)
566 {
567         const uint8_t *s = src;
568
569         s += offset;
570         return read_ble8(s);
571 }
572
573 static inline void write_ble8(void *dest, uint8_t val)
574 {
575         *(uint8_t *)dest = val;
576 }
577
578 static inline void write_at_ble8(void *dest, uint8_t val, size_t offset)
579 {
580         uint8_t *d = dest;
581
582         d += offset;
583         write_ble8(d, val);
584 }
585
586 static inline uint8_t read_at_le8(const void *src, size_t offset)
587 {
588         return read_at_ble8(src, offset);
589 }
590
591 static inline void write_le8(void *dest, uint8_t val)
592 {
593         write_ble8(dest, val);
594 }
595
596 static inline void write_at_le8(void *dest, uint8_t val, size_t offset)
597 {
598         write_at_ble8(dest, val, offset);
599 }
600
601 static inline uint16_t read_le16(const void *src)
602 {
603         const uint8_t *s = src;
604
605         return (((uint16_t)s[1]) << 8) | (((uint16_t)s[0]) << 0);
606 }
607
608 static inline uint16_t read_at_le16(const void *src, size_t offset)
609 {
610         const uint8_t *s = src;
611
612         s += offset;
613         return read_le16(s);
614 }
615
616 static inline void write_le16(void *dest, uint16_t val)
617 {
618         write_le8(dest, val >> 0);
619         write_at_le8(dest, val >> 8, sizeof(uint8_t));
620 }
621
622 static inline void write_at_le16(void *dest, uint16_t val, size_t offset)
623 {
624         uint8_t *d = dest;
625
626         d += offset;
627         write_le16(d, val);
628 }
629
630 static inline uint32_t read_le32(const void *src)
631 {
632         const uint8_t *s = src;
633
634         return (((uint32_t)s[3]) << 24) | (((uint32_t)s[2]) << 16) |
635                 (((uint32_t)s[1]) << 8) | (((uint32_t)s[0]) << 0);
636 }
637
638 static inline uint32_t read_at_le32(const void *src, size_t offset)
639 {
640         const uint8_t *s = src;
641
642         s += offset;
643         return read_le32(s);
644 }
645
646 static inline void write_le32(void *dest, uint32_t val)
647 {
648         write_le16(dest, val >> 0);
649         write_at_le16(dest, val >> 16, sizeof(uint16_t));
650 }
651
652 static inline void write_at_le32(void *dest, uint32_t val, size_t offset)
653 {
654         uint8_t *d = dest;
655
656         d += offset;
657         write_le32(d, val);
658 }
659
660 static inline uint64_t read_le64(const void *src)
661 {
662         uint64_t val;
663
664         val = read_at_le32(src, sizeof(uint32_t));
665         val <<= 32;
666         val |= read_le32(src);
667         return val;
668 }
669
670 static inline uint64_t read_at_le64(const void *src, size_t offset)
671 {
672         const uint8_t *s = src;
673
674         s += offset;
675         return read_le64(s);
676 }
677
678 static inline void write_le64(void *dest, uint64_t val)
679 {
680         write_le32(dest, val >> 0);
681         write_at_le32(dest, val >> 32, sizeof(uint32_t));
682 }
683
684 static inline void write_at_le64(void *dest, uint64_t val, size_t offset)
685 {
686         uint8_t *d = dest;
687
688         d += offset;
689         write_le64(d, val);
690 }
691
692 /*
693  * Read header/entry members in little-endian format.
694  * Returns the offset upto which the read was performed.
695  */
696 static size_t read_member(void *src, size_t offset, size_t size_bytes,
697                           void *dst)
698 {
699         switch (size_bytes) {
700         case 1:
701                 *(uint8_t *)dst = read_at_le8(src, offset);
702                 break;
703         case 2:
704                 *(uint16_t *)dst = read_at_le16(src, offset);
705                 break;
706         case 4:
707                 *(uint32_t *)dst = read_at_le32(src, offset);
708                 break;
709         case 8:
710                 *(uint64_t *)dst = read_at_le64(src, offset);
711                 break;
712         default:
713                 ERROR("Read size not supported %zd\n", size_bytes);
714                 exit(-1);
715         }
716
717         return (offset + size_bytes);
718 }
719
720 /*
721  * Convert to little endian format.
722  * Returns the offset upto which the fixup was performed.
723  */
724 static size_t fix_member(void *data, size_t offset, size_t size_bytes)
725 {
726         uint8_t *src = (uint8_t *)data + offset;
727
728         switch (size_bytes) {
729         case 1:
730                 write_at_le8(data, *(uint8_t *)src, offset);
731                 break;
732         case 2:
733                 write_at_le16(data, *(uint16_t *)src, offset);
734                 break;
735         case 4:
736                 write_at_le32(data, *(uint32_t *)src, offset);
737                 break;
738         case 8:
739                 write_at_le64(data, *(uint64_t *)src, offset);
740                 break;
741         default:
742                 ERROR("Write size not supported %zd\n", size_bytes);
743                 exit(-1);
744         }
745         return (offset + size_bytes);
746 }
747
748 static void print_subpart_dir(struct subpart_dir *s)
749 {
750         if (verbose == 0)
751                 return;
752
753         size_t i;
754
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]);
764
765         printf("\n");
766
767         printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
768                "Length", "Rsvd");
769
770         printf("=========================================================================================================================\n");
771
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,
775                        s->e[i].rsvd);
776         }
777
778         printf("=========================================================================================================================\n");
779 }
780
781 static void bpdt_print_header(struct bpdt_header *h, const char *name)
782 {
783         if (verbose == 0)
784                 return;
785
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);
794 }
795
796 static void bpdt_print_entries(struct bpdt_entry *e, size_t count,
797                                const char *name)
798 {
799         size_t i;
800
801         if (verbose == 0)
802                 return;
803
804         printf("%s entries\n", name);
805
806         printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
807                "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
808                "File Offset");
809
810         printf("=========================================================================================================================================================================================================\n");
811
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);
818         }
819
820         printf("=========================================================================================================================================================================================================\n");
821 }
822
823 static void bpdt_validate_header(struct bpdt_header *h, const char *name)
824 {
825         assert(h->signature == BPDT_SIGNATURE);
826
827         if (h->bpdt_version != 1) {
828                 ERROR("Invalid header : %s\n", name);
829                 exit(-1);
830         }
831
832         DEBUG("Validated header : %s\n", name);
833 }
834
835 static void bpdt_read_header(void *data, struct bpdt_header *h,
836                              const char *name)
837 {
838         size_t offset = 0;
839
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),
844                              &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),
848                              &h->ifwi_version);
849         read_member(data, offset, sizeof(h->fit_tool_version),
850                     &h->fit_tool_version);
851
852         bpdt_validate_header(h, name);
853         bpdt_print_header(h, name);
854 }
855
856 static void bpdt_read_entries(void *data, struct bpdt *bpdt, const char *name)
857 {
858         size_t i, offset = 0;
859         struct bpdt_entry *e = &bpdt->e[0];
860         size_t count = bpdt->h.descriptor_count;
861
862         for (i = 0; i < count; i++) {
863                 offset = read_member(data, offset, sizeof(e[i].type),
864                                      &e[i].type);
865                 offset = read_member(data, offset, sizeof(e[i].flags),
866                                      &e[i].flags);
867                 offset = read_member(data, offset, sizeof(e[i].offset),
868                                      &e[i].offset);
869                 offset = read_member(data, offset, sizeof(e[i].size),
870                                      &e[i].size);
871         }
872
873         bpdt_print_entries(e, count, name);
874 }
875
876 /*
877  * Given type of sub-partition, identify BPDT entry for it.
878  * Sub-Partition could lie either within BPDT or S-BPDT.
879  */
880 static struct bpdt_entry *__find_entry_by_type(struct bpdt_entry *e,
881                                                size_t count, int type)
882 {
883         size_t i;
884
885         for (i = 0; i < count; i++) {
886                 if (e[i].type == type)
887                         break;
888         }
889
890         if (i == count)
891                 return NULL;
892
893         return &e[i];
894 }
895
896 static struct bpdt_entry *find_entry_by_type(int type)
897 {
898         struct bpdt *b = buffer_get(&ifwi_image.bpdt);
899
900         if (!b)
901                 return NULL;
902
903         struct bpdt_entry *curr = __find_entry_by_type(&b->e[0],
904                                                        b->h.descriptor_count,
905                                                        type);
906
907         if (curr)
908                 return curr;
909
910         b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
911         if (!b)
912                 return NULL;
913
914         return __find_entry_by_type(&b->e[0], b->h.descriptor_count, type);
915 }
916
917 /*
918  * Find sub-partition type given its name. If the name does not exist, returns
919  * -1.
920  */
921 static int find_type_by_name(const char *name)
922 {
923         int i;
924
925         for (i = 0; i < MAX_SUBPARTS; i++) {
926                 if ((strlen(subparts[i].name) == strlen(name)) &&
927                     (!strcmp(subparts[i].name, name)))
928                         break;
929         }
930
931         if (i == MAX_SUBPARTS) {
932                 ERROR("Invalid sub-partition name %s.\n", name);
933                 return -1;
934         }
935
936         return i;
937 }
938
939 /*
940  * Read the content of a sub-partition from input file and store it in
941  * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
942  *
943  * Returns the maximum offset occupied by the sub-partitions.
944  */
945 static size_t read_subpart_buf(void *data, size_t size, struct bpdt_entry *e,
946                                size_t count)
947 {
948         size_t i, type;
949         struct buffer *buf;
950         size_t max_offset = 0;
951
952         for (i = 0; i < count; i++) {
953                 type = e[i].type;
954
955                 if (type >= MAX_SUBPARTS) {
956                         ERROR("Invalid sub-partition type %zd.\n", type);
957                         exit(-1);
958                 }
959
960                 if (buffer_size(&ifwi_image.subpart_buf[type])) {
961                         ERROR("Multiple sub-partitions of type %zd(%s).\n",
962                               type, subparts[type].name);
963                         exit(-1);
964                 }
965
966                 if (e[i].size == 0) {
967                         INFO("Dummy sub-partition %zd(%s). Skipping.\n", type,
968                              subparts[type].name);
969                         continue;
970                 }
971
972                 assert((e[i].offset + e[i].size) <= size);
973
974                 /*
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.
978                  */
979                 if ((e[i].offset + e[i].size) > max_offset)
980                         max_offset = e[i].offset + e[i].size;
981
982                 /*
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.
990                  */
991                 if (type == S_BPDT_TYPE)
992                         continue;
993
994                 buf = &ifwi_image.subpart_buf[type];
995
996                 alloc_buffer(buf, e[i].size, subparts[type].name);
997                 memcpy(buffer_get(buf), (uint8_t *)data + e[i].offset,
998                        e[i].size);
999         }
1000
1001         assert(max_offset);
1002         return max_offset;
1003 }
1004
1005 /*
1006  * Allocate buffer for bpdt header, entries and all sub-partition content.
1007  * Returns offset in data where BPDT ends.
1008  */
1009 static size_t alloc_bpdt_buffer(void *data, size_t size, size_t offset,
1010                                 struct buffer *b, const char *name)
1011 {
1012         struct bpdt_header bpdt_header;
1013
1014         assert((offset + BPDT_HEADER_SIZE) < size);
1015         bpdt_read_header((uint8_t *)data + offset, &bpdt_header, name);
1016
1017         /* Buffer to read BPDT header and entries */
1018         alloc_buffer(b, get_bpdt_size(&bpdt_header), name);
1019
1020         struct bpdt *bpdt = buffer_get(b);
1021
1022         memcpy(&bpdt->h, &bpdt_header, BPDT_HEADER_SIZE);
1023
1024         /*
1025          * If no entries are present, maximum offset occupied is (offset +
1026          * BPDT_HEADER_SIZE).
1027          */
1028         if (bpdt->h.descriptor_count == 0)
1029                 return (offset + BPDT_HEADER_SIZE);
1030
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,
1034                           name);
1035
1036         /* Read all sub-partition content in subpart_buf */
1037         return read_subpart_buf(data, size, &bpdt->e[0],
1038                                 bpdt->h.descriptor_count);
1039 }
1040
1041 static void parse_sbpdt(void *data, size_t size)
1042 {
1043         struct bpdt_entry *s;
1044
1045         s  = find_entry_by_type(S_BPDT_TYPE);
1046         if (!s)
1047                 return;
1048
1049         assert(size > s->offset);
1050
1051         alloc_bpdt_buffer(data, size, s->offset,
1052                           &ifwi_image.subpart_buf[S_BPDT_TYPE],
1053                           "S-BPDT");
1054 }
1055
1056 static uint8_t calc_checksum(struct subpart_dir *s)
1057 {
1058         size_t size = subpart_dir_size(&s->h);
1059         uint8_t *data = (uint8_t *)s;
1060         uint8_t checksum = 0;
1061         size_t i;
1062         uint8_t old_checksum = s->h.checksum;
1063
1064         s->h.checksum = 0;
1065
1066         for (i = 0; i < size; i++)
1067                 checksum += data[i];
1068
1069         s->h.checksum = old_checksum;
1070
1071         /* 2s complement */
1072         return -checksum;
1073 }
1074
1075 static void validate_subpart_dir(struct subpart_dir *s, const char *name,
1076                                  bool checksum_check)
1077 {
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);
1083                 exit(-1);
1084         }
1085
1086         if (!checksum_check)
1087                 return;
1088
1089         uint8_t checksum = calc_checksum(s);
1090
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);
1094 }
1095
1096 static void validate_subpart_dir_without_checksum(struct subpart_dir *s,
1097                                                   const char *name)
1098 {
1099         validate_subpart_dir(s, name, 0);
1100 }
1101
1102 static void validate_subpart_dir_with_checksum(struct subpart_dir *s,
1103                                                const char *name)
1104 {
1105         validate_subpart_dir(s, name, 1);
1106 }
1107
1108 static void parse_subpart_dir(struct buffer *subpart_dir_buf,
1109                               struct buffer *input_buf, const char *name)
1110 {
1111         struct subpart_dir_header hdr;
1112         size_t offset = 0;
1113         uint8_t *data = buffer_get(input_buf);
1114         size_t size = buffer_size(input_buf);
1115
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),
1120                              &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);
1130
1131         validate_subpart_dir_without_checksum((struct subpart_dir *)&hdr, name);
1132
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);
1136
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];
1140         uint32_t i;
1141
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),
1146                                      &e[i].offset);
1147                 offset = read_member(data, offset, sizeof(e[i].length),
1148                                      &e[i].length);
1149                 offset = read_member(data, offset, sizeof(e[i].rsvd),
1150                                      &e[i].rsvd);
1151         }
1152
1153         validate_subpart_dir_with_checksum(subpart_dir, name);
1154
1155         print_subpart_dir(subpart_dir);
1156 }
1157
1158 /* Parse input image file to identify different sub-partitions */
1159 static int ifwi_parse(void)
1160 {
1161         struct buffer *buff = &ifwi_image.input_buff;
1162         const char *image_name = param.image_name;
1163
1164         DEBUG("Parsing IFWI image...\n");
1165
1166         /* Read input file */
1167         if (buffer_from_file(buff, image_name)) {
1168                 ERROR("Failed to read input file %s.\n", image_name);
1169                 return -1;
1170         }
1171
1172         INFO("Buffer %p size 0x%zx\n", buff->data, buff->size);
1173
1174         /* Look for BPDT signature at 4K intervals */
1175         size_t offset = 0;
1176         void *data = buffer_get(buff);
1177
1178         while (offset < buffer_size(buff)) {
1179                 if (read_at_le32(data, offset) == BPDT_SIGNATURE)
1180                         break;
1181                 offset += 4 * KiB;
1182         }
1183
1184         if (offset >= buffer_size(buff)) {
1185                 ERROR("Image does not contain BPDT!!\n");
1186                 return -1;
1187         }
1188
1189         ifwi_image.input_ifwi_start_offset = offset;
1190         INFO("BPDT starts at offset 0x%zx.\n", offset);
1191
1192         data = (uint8_t *)data + offset;
1193         size_t ifwi_size = buffer_size(buff) - offset;
1194
1195         /* Read BPDT and sub-partitions */
1196         uintptr_t end_offset;
1197
1198         end_offset = ifwi_image.input_ifwi_start_offset +
1199                 alloc_bpdt_buffer(data, ifwi_size, 0, &ifwi_image.bpdt, "BPDT");
1200
1201         /* Parse S-BPDT, if any */
1202         parse_sbpdt(data, ifwi_size);
1203
1204         /*
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.
1208          */
1209         ifwi_image.input_ifwi_end_offset = ALIGN(end_offset, 4 * KiB);
1210         DEBUG("Parsing done.\n");
1211
1212         return 0;
1213 }
1214
1215 /*
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.
1220  */
1221 static void __bpdt_reset(struct buffer *b, size_t count, size_t size)
1222 {
1223         size_t bpdt_size = BPDT_HEADER_SIZE + count * BPDT_ENTRY_SIZE;
1224
1225         assert(size >= bpdt_size);
1226
1227         /*
1228          * If buffer does not have the required size, allocate a fresh buffer.
1229          */
1230         if (buffer_size(b) != size) {
1231                 struct buffer temp;
1232
1233                 alloc_buffer(&temp, size, b->name);
1234                 memcpy(buffer_get(&temp), buffer_get(b), buffer_size(b));
1235                 buffer_delete(b);
1236                 *b = temp;
1237         }
1238
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;
1242
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);
1247
1248         bpdt->h.descriptor_count = count;
1249 }
1250
1251 static void bpdt_reset(void)
1252 {
1253         size_t i;
1254         size_t bpdt_count = 0, sbpdt_count = 0, dummy_bpdt_count = 0;
1255
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) {
1260                                 bpdt_count++;
1261                                 dummy_bpdt_count++;
1262                         }
1263                         continue;
1264                 }
1265
1266                 if (subparts[i].attr & NON_CRITICAL_SUBPART)
1267                         sbpdt_count++;
1268                 else
1269                         bpdt_count++;
1270         }
1271
1272         DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count,
1273               dummy_bpdt_count, sbpdt_count);
1274
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);
1279
1280         /* Update S-BPDT if required */
1281         bpdt_size = ALIGN(BPDT_HEADER_SIZE + sbpdt_count * BPDT_ENTRY_SIZE,
1282                           4 * KiB);
1283         __bpdt_reset(&ifwi_image.subpart_buf[S_BPDT_TYPE], sbpdt_count,
1284                      bpdt_size);
1285 }
1286
1287 /* Initialize BPDT entries in header order */
1288 static void bpdt_entries_init_header_order(void)
1289 {
1290         int i, type;
1291         size_t size;
1292
1293         struct bpdt *bpdt, *sbpdt, *curr;
1294         size_t bpdt_curr = 0, sbpdt_curr = 0, *count_ptr;
1295
1296         bpdt = buffer_get(&ifwi_image.bpdt);
1297         sbpdt = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1298
1299         for (i = 0; i < MAX_SUBPARTS; i++) {
1300                 type = bpdt_header_order[i];
1301                 size = buffer_size(&ifwi_image.subpart_buf[type]);
1302
1303                 if (size == 0 && !(subparts[type].attr & MANDATORY_BPDT_ENTRY))
1304                         continue;
1305
1306                 if (subparts[type].attr & NON_CRITICAL_SUBPART) {
1307                         curr = sbpdt;
1308                         count_ptr = &sbpdt_curr;
1309                 } else {
1310                         curr = bpdt;
1311                         count_ptr = &bpdt_curr;
1312                 }
1313
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;
1319
1320                 (*count_ptr)++;
1321         }
1322 }
1323
1324 static void pad_buffer(struct buffer *b, size_t size)
1325 {
1326         size_t buff_size = buffer_size(b);
1327
1328         assert(buff_size <= size);
1329
1330         if (buff_size == size)
1331                 return;
1332
1333         struct buffer temp;
1334
1335         alloc_buffer(&temp, size, b->name);
1336         uint8_t *data = buffer_get(&temp);
1337
1338         memcpy(data, buffer_get(b), buff_size);
1339         memset(data + buff_size, 0xFF, size - buff_size);
1340
1341         *b = temp;
1342 }
1343
1344 /* Initialize offsets of entries using pack order */
1345 static void bpdt_entries_init_pack_order(void)
1346 {
1347         int i, type;
1348         struct bpdt_entry *curr;
1349         size_t curr_offset, curr_end;
1350
1351         curr_offset = max(BPDT_MIN_SIZE, buffer_size(&ifwi_image.bpdt));
1352
1353         /*
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
1357          *
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
1363          * unchanged.
1364          *
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.
1368          */
1369
1370         /* #1 Sub-partitions that lie within same 4K as BPDT */
1371         struct buffer *last_bpdt_buff = &ifwi_image.bpdt;
1372
1373         for (i = 0; i < MAX_SUBPARTS; i++) {
1374                 type = bpdt_pack_order[i];
1375                 curr = find_entry_by_type(type);
1376
1377                 if (!curr || curr->size == 0)
1378                         continue;
1379
1380                 if (!(subparts[type].attr & LIES_WITHIN_BPDT_4K))
1381                         continue;
1382
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]));
1389         }
1390
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;
1396
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);
1401
1402                 if (!curr || curr->size == 0)
1403                         continue;
1404
1405                 if (subparts[type].attr & LIES_WITHIN_BPDT_4K)
1406                         continue;
1407
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;
1412
1413                 pad_buffer(&ifwi_image.subpart_buf[type], curr->size);
1414
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]));
1419         }
1420
1421         /*
1422          * Update size of S-BPDT to include size of all non-critical
1423          * sub-partitions.
1424          *
1425          * Assumption: S-BPDT always lies at the end of IFWI image.
1426          */
1427         curr = find_entry_by_type(S_BPDT_TYPE);
1428         assert(curr);
1429
1430         assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1431         curr->size = curr_offset - curr->offset;
1432 }
1433
1434 /* Convert all members of BPDT to little-endian format */
1435 static void bpdt_fixup_write_buffer(struct buffer *buf)
1436 {
1437         struct bpdt *s = buffer_get(buf);
1438
1439         struct bpdt_header *h = &s->h;
1440         struct bpdt_entry *e = &s->e[0];
1441
1442         size_t count = h->descriptor_count;
1443
1444         size_t offset = 0;
1445
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));
1455
1456         uint32_t i;
1457
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));
1463         }
1464 }
1465
1466 /* Write BPDT to output buffer after fixup */
1467 static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src)
1468 {
1469         bpdt_fixup_write_buffer(src);
1470         memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src));
1471 }
1472
1473 /*
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.
1479  *
1480  * While performing the above steps, make sure that any empty holes are filled
1481  * with FF.
1482  */
1483 static void ifwi_write(const char *image_name)
1484 {
1485         struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE);
1486
1487         assert(s);
1488
1489         size_t ifwi_start, ifwi_end, file_end;
1490
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);
1495
1496         struct buffer b;
1497
1498         alloc_buffer(&b, file_end, "Final-IFWI");
1499
1500         uint8_t *input_data = buffer_get(&ifwi_image.input_buff);
1501         uint8_t *output_data = buffer_get(&b);
1502
1503         DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start,
1504               ifwi_end, file_end);
1505
1506         /* Copy non-IFWI prefix, if any */
1507         memcpy(output_data, input_data, ifwi_start);
1508
1509         DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start);
1510
1511         struct buffer ifwi;
1512
1513         buffer_splice(&ifwi, &b, ifwi_start, ifwi_end - ifwi_start);
1514         uint8_t *ifwi_data = buffer_get(&ifwi);
1515
1516         /* Copy sub-partitions using pack_order */
1517         struct bpdt_entry *curr;
1518         struct buffer *subpart_buf;
1519         int i, type;
1520
1521         for (i = 0; i < MAX_SUBPARTS; i++) {
1522                 type = bpdt_pack_order[i];
1523
1524                 if (type == S_BPDT_TYPE)
1525                         continue;
1526
1527                 curr = find_entry_by_type(type);
1528
1529                 if (!curr || !curr->size)
1530                         continue;
1531
1532                 subpart_buf = &ifwi_image.subpart_buf[type];
1533
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));
1536
1537                 assert((curr->offset + buffer_size(subpart_buf)) <=
1538                        buffer_size(&ifwi));
1539
1540                 memcpy(ifwi_data + curr->offset, buffer_get(subpart_buf),
1541                        buffer_size(subpart_buf));
1542         }
1543
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);
1551         }
1552
1553         /*
1554          * Convert BPDT to little-endian format and write it to output buffer.
1555          * S-BPDT is written first and then BPDT.
1556          */
1557         bpdt_write(&ifwi, s->offset, &ifwi_image.subpart_buf[S_BPDT_TYPE]);
1558         bpdt_write(&ifwi, 0, &ifwi_image.bpdt);
1559
1560         if (buffer_write_file(&b, image_name)) {
1561                 ERROR("File write error\n");
1562                 exit(-1);
1563         }
1564
1565         buffer_delete(&b);
1566         printf("Image written successfully to %s.\n", image_name);
1567 }
1568
1569 /*
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.
1573  */
1574 static void ifwi_repack(void)
1575 {
1576         bpdt_reset();
1577         bpdt_entries_init_header_order();
1578         bpdt_entries_init_pack_order();
1579
1580         struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1581
1582         bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1583
1584         b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1585         bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1586
1587         DEBUG("Repack done.. writing image.\n");
1588         ifwi_write(param.image_name);
1589 }
1590
1591 static void init_subpart_dir_header(struct subpart_dir_header *hdr,
1592                                     size_t count, const char *name)
1593 {
1594         memset(hdr, 0, sizeof(*hdr));
1595
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));
1602 }
1603
1604 static size_t init_subpart_dir_entry(struct subpart_dir_entry *e,
1605                                      struct buffer *b, size_t offset)
1606 {
1607         memset(e, 0, sizeof(*e));
1608
1609         assert(strlen(b->name) <= sizeof(e->name));
1610         strncpy((char *)e->name, (char *)b->name, sizeof(e->name));
1611         e->offset = offset;
1612         e->length = buffer_size(b);
1613
1614         return (offset + buffer_size(b));
1615 }
1616
1617 static void init_manifest_header(struct manifest_header *hdr, size_t size)
1618 {
1619         memset(hdr, 0, sizeof(*hdr));
1620
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;
1626
1627         struct tm *local_time;
1628         time_t curr_time;
1629         char buffer[11];
1630
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);
1635
1636         assert((size % DWORD_SIZE) == 0);
1637         hdr->size = size / DWORD_SIZE;
1638         hdr->id = MANIFEST_ID_MAGIC;
1639 }
1640
1641 static void init_signed_pkg_info_ext(struct signed_pkg_info_ext *ext,
1642                                      size_t count, const char *name)
1643 {
1644         memset(ext, 0, sizeof(*ext));
1645
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));
1649 }
1650
1651 static void subpart_dir_fixup_write_buffer(struct buffer *buf)
1652 {
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];
1656
1657         size_t count = h->num_entries;
1658         size_t offset = 0;
1659
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);
1670
1671         uint32_t i;
1672
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));
1678         }
1679 }
1680
1681 static void create_subpart(struct buffer *dst, struct buffer *info[],
1682                            size_t count, const char *name)
1683 {
1684         struct buffer subpart_dir_buff;
1685         size_t size = SUBPART_DIR_HEADER_SIZE + count * SUBPART_DIR_ENTRY_SIZE;
1686
1687         alloc_buffer(&subpart_dir_buff, size, "subpart-dir");
1688
1689         struct subpart_dir_header *h = buffer_get(&subpart_dir_buff);
1690         struct subpart_dir_entry *e = (struct subpart_dir_entry *)(h + 1);
1691
1692         init_subpart_dir_header(h, count, name);
1693
1694         size_t curr_offset = size;
1695         size_t i;
1696
1697         for (i = 0; i < count; i++) {
1698                 curr_offset = init_subpart_dir_entry(&e[i], info[i],
1699                                                      curr_offset);
1700         }
1701
1702         alloc_buffer(dst, curr_offset, name);
1703         uint8_t *data = buffer_get(dst);
1704
1705         for (i = 0; i < count; i++) {
1706                 memcpy(data + e[i].offset, buffer_get(info[i]),
1707                        buffer_size(info[i]));
1708         }
1709
1710         h->checksum = calc_checksum(buffer_get(&subpart_dir_buff));
1711
1712         struct subpart_dir *dir = buffer_get(&subpart_dir_buff);
1713
1714         print_subpart_dir(dir);
1715
1716         subpart_dir_fixup_write_buffer(&subpart_dir_buff);
1717         memcpy(data, dir, buffer_size(&subpart_dir_buff));
1718
1719         buffer_delete(&subpart_dir_buff);
1720 }
1721
1722 static enum ifwi_ret ibbp_dir_add(int type)
1723 {
1724         struct buffer manifest;
1725         struct signed_pkg_info_ext *ext;
1726         struct buffer ibbl;
1727         struct buffer ibb;
1728
1729 #define DUMMY_IBB_SIZE                  (4 * KiB)
1730
1731         assert(type == IBB_TYPE);
1732
1733         /*
1734          * Entry # 1 - IBBP.man
1735          * Contains manifest header and signed pkg info extension.
1736          */
1737         size_t size = MANIFEST_HDR_SIZE + SIGNED_PKG_INFO_EXT_SIZE;
1738
1739         alloc_buffer(&manifest, size, "IBBP.man");
1740
1741         struct manifest_header *man_hdr = buffer_get(&manifest);
1742
1743         init_manifest_header(man_hdr, size);
1744
1745         ext = (struct signed_pkg_info_ext *)(man_hdr + 1);
1746
1747         init_signed_pkg_info_ext(ext, 0, subparts[type].name);
1748
1749         /* Entry # 2 - IBBL */
1750         if (buffer_from_file(&ibbl, param.file_name))
1751                 return COMMAND_ERR;
1752
1753         /* Entry # 3 - IBB */
1754         alloc_buffer(&ibb, DUMMY_IBB_SIZE, "IBB");
1755         memset(buffer_get(&ibb), 0xFF, DUMMY_IBB_SIZE);
1756
1757         /* Create subpartition */
1758         struct buffer *info[] = {
1759                 &manifest, &ibbl, &ibb,
1760         };
1761         create_subpart(&ifwi_image.subpart_buf[type], &info[0],
1762                        ARRAY_SIZE(info), subparts[type].name);
1763
1764         return REPACK_REQUIRED;
1765 }
1766
1767 static enum ifwi_ret ifwi_raw_add(int type)
1768 {
1769         if (buffer_from_file(&ifwi_image.subpart_buf[type], param.file_name))
1770                 return COMMAND_ERR;
1771
1772         printf("Sub-partition %s(%d) added from file %s.\n", param.subpart_name,
1773                type, param.file_name);
1774         return REPACK_REQUIRED;
1775 }
1776
1777 static enum ifwi_ret ifwi_dir_add(int type)
1778 {
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);
1783                 return COMMAND_ERR;
1784         }
1785
1786         if (!param.dentry_name) {
1787                 ERROR("%s: -e option required\n", __func__);
1788                 return COMMAND_ERR;
1789         }
1790
1791         enum ifwi_ret ret = subparts[type].dir_ops.dir_add(type);
1792
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,
1796                        param.file_name);
1797         else
1798                 ERROR("Sub-partition dir operation failed.\n");
1799
1800         return ret;
1801 }
1802
1803 static enum ifwi_ret ifwi_add(void)
1804 {
1805         if (!param.file_name) {
1806                 ERROR("%s: -f option required\n", __func__);
1807                 return COMMAND_ERR;
1808         }
1809
1810         if (!param.subpart_name) {
1811                 ERROR("%s: -n option required\n", __func__);
1812                 return COMMAND_ERR;
1813         }
1814
1815         int type = find_type_by_name(param.subpart_name);
1816
1817         if (type == -1)
1818                 return COMMAND_ERR;
1819
1820         const struct subpart_info *curr_subpart = &subparts[type];
1821
1822         if (curr_subpart->attr & AUTO_GENERATED) {
1823                 ERROR("Cannot add auto-generated sub-partitions.\n");
1824                 return COMMAND_ERR;
1825         }
1826
1827         if (buffer_size(&ifwi_image.subpart_buf[type])) {
1828                 ERROR("Image already contains sub-partition %s(%d).\n",
1829                       param.subpart_name, type);
1830                 return COMMAND_ERR;
1831         }
1832
1833         if (param.dir_ops)
1834                 return ifwi_dir_add(type);
1835
1836         return ifwi_raw_add(type);
1837 }
1838
1839 static enum ifwi_ret ifwi_delete(void)
1840 {
1841         if (!param.subpart_name) {
1842                 ERROR("%s: -n option required\n", __func__);
1843                 return COMMAND_ERR;
1844         }
1845
1846         int type = find_type_by_name(param.subpart_name);
1847
1848         if (type == -1)
1849                 return COMMAND_ERR;
1850
1851         const struct subpart_info *curr_subpart = &subparts[type];
1852
1853         if (curr_subpart->attr & AUTO_GENERATED) {
1854                 ERROR("Cannot delete auto-generated sub-partitions.\n");
1855                 return COMMAND_ERR;
1856         }
1857
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;
1862         }
1863
1864         buffer_delete(&ifwi_image.subpart_buf[type]);
1865         printf("Sub-Partition %s(%d) deleted.\n", subparts[type].name, type);
1866         return REPACK_REQUIRED;
1867 }
1868
1869 static enum ifwi_ret ifwi_dir_extract(int type)
1870 {
1871         if (!(subparts[type].attr & CONTAINS_DIR)) {
1872                 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1873                       subparts[type].name, type);
1874                 return COMMAND_ERR;
1875         }
1876
1877         if (!param.dentry_name) {
1878                 ERROR("%s: -e option required.\n", __func__);
1879                 return COMMAND_ERR;
1880         }
1881
1882         struct buffer subpart_dir_buff;
1883
1884         parse_subpart_dir(&subpart_dir_buff, &ifwi_image.subpart_buf[type],
1885                           subparts[type].name);
1886
1887         uint32_t i;
1888         struct subpart_dir *s = buffer_get(&subpart_dir_buff);
1889
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)))
1893                         break;
1894         }
1895
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);
1899                 exit(-1);
1900         }
1901
1902         struct buffer dst;
1903
1904         DEBUG("Splicing buffer at 0x%x size 0x%x\n", s->e[i].offset,
1905               s->e[i].length);
1906         buffer_splice(&dst, &ifwi_image.subpart_buf[type], s->e[i].offset,
1907                       s->e[i].length);
1908
1909         if (buffer_write_file(&dst, param.file_name))
1910                 return COMMAND_ERR;
1911
1912         printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1913                param.subpart_name, type, param.dentry_name, param.file_name);
1914
1915         return NO_ACTION_REQUIRED;
1916 }
1917
1918 static enum ifwi_ret ifwi_raw_extract(int type)
1919 {
1920         if (buffer_write_file(&ifwi_image.subpart_buf[type], param.file_name))
1921                 return COMMAND_ERR;
1922
1923         printf("Sub-Partition %s(%d) stored in %s.\n", param.subpart_name, type,
1924                param.file_name);
1925
1926         return NO_ACTION_REQUIRED;
1927 }
1928
1929 static enum ifwi_ret ifwi_extract(void)
1930 {
1931         if (!param.file_name) {
1932                 ERROR("%s: -f option required\n", __func__);
1933                 return COMMAND_ERR;
1934         }
1935
1936         if (!param.subpart_name) {
1937                 ERROR("%s: -n option required\n", __func__);
1938                 return COMMAND_ERR;
1939         }
1940
1941         int type = find_type_by_name(param.subpart_name);
1942
1943         if (type == -1)
1944                 return COMMAND_ERR;
1945
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;
1950         }
1951
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);
1955                 return COMMAND_ERR;
1956         }
1957
1958         INFO("Extracting sub-partition %s(%d).\n", param.subpart_name, type);
1959         if (param.dir_ops)
1960                 return ifwi_dir_extract(type);
1961
1962         return ifwi_raw_extract(type);
1963 }
1964
1965 static enum ifwi_ret ifwi_print(void)
1966 {
1967         verbose += 2;
1968
1969         struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1970
1971         bpdt_print_header(&b->h, "BPDT");
1972         bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1973
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");
1977
1978         if (param.dir_ops == 0) {
1979                 verbose -= 2;
1980                 return NO_ACTION_REQUIRED;
1981         }
1982
1983         int i;
1984         struct buffer subpart_dir_buf;
1985
1986         for (i = 0; i < MAX_SUBPARTS ; i++) {
1987                 if (!(subparts[i].attr & CONTAINS_DIR) ||
1988                     (buffer_size(&ifwi_image.subpart_buf[i]) == 0))
1989                         continue;
1990
1991                 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[i],
1992                                   subparts[i].name);
1993                 buffer_delete(&subpart_dir_buf);
1994         }
1995
1996         verbose -= 2;
1997
1998         return NO_ACTION_REQUIRED;
1999 }
2000
2001 static enum ifwi_ret ifwi_raw_replace(int type)
2002 {
2003         buffer_delete(&ifwi_image.subpart_buf[type]);
2004         return ifwi_raw_add(type);
2005 }
2006
2007 static enum ifwi_ret ifwi_dir_replace(int type)
2008 {
2009         if (!(subparts[type].attr & CONTAINS_DIR)) {
2010                 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
2011                       subparts[type].name, type);
2012                 return COMMAND_ERR;
2013         }
2014
2015         if (!param.dentry_name) {
2016                 ERROR("%s: -e option required.\n", __func__);
2017                 return COMMAND_ERR;
2018         }
2019
2020         struct buffer subpart_dir_buf;
2021
2022         parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[type],
2023                           subparts[type].name);
2024
2025         uint32_t i;
2026         struct subpart_dir *s = buffer_get(&subpart_dir_buf);
2027
2028         for (i = 0; i < s->h.num_entries; i++) {
2029                 if (!strcmp((char *)s->e[i].name, param.dentry_name))
2030                         break;
2031         }
2032
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);
2036                 exit(-1);
2037         }
2038
2039         struct buffer b;
2040
2041         if (buffer_from_file(&b, param.file_name)) {
2042                 ERROR("Failed to read %s\n", param.file_name);
2043                 exit(-1);
2044         }
2045
2046         struct buffer dst;
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;
2051
2052         alloc_buffer(&dst, dst_size, ifwi_image.subpart_buf[type].name);
2053
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;
2057
2058         /* Copy data before the sub-partition entry */
2059         memcpy(dst_data + curr_offset, src_data, subpart_start);
2060         curr_offset += subpart_start;
2061
2062         /* Copy sub-partition entry */
2063         memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
2064         curr_offset += buffer_size(&b);
2065
2066         /* Copy remaining data */
2067         memcpy(dst_data + curr_offset, src_data + subpart_end,
2068                buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end);
2069
2070         /* Update sub-partition buffer */
2071         int offset = s->e[i].offset;
2072
2073         buffer_delete(&ifwi_image.subpart_buf[type]);
2074         ifwi_image.subpart_buf[type] = dst;
2075
2076         /* Update length of entry in the subpartition */
2077         s->e[i].length = buffer_size(&b);
2078         buffer_delete(&b);
2079
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;
2084
2085         /* Re-calculate checksum */
2086         s->h.checksum = calc_checksum(s);
2087
2088         /* Convert members to litte-endian */
2089         subpart_dir_fixup_write_buffer(&subpart_dir_buf);
2090
2091         memcpy(dst_data, buffer_get(&subpart_dir_buf),
2092                buffer_size(&subpart_dir_buf));
2093
2094         buffer_delete(&subpart_dir_buf);
2095
2096         printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
2097                param.subpart_name, type, param.dentry_name, param.file_name);
2098
2099         return REPACK_REQUIRED;
2100 }
2101
2102 static enum ifwi_ret ifwi_replace(void)
2103 {
2104         if (!param.file_name) {
2105                 ERROR("%s: -f option required\n", __func__);
2106                 return COMMAND_ERR;
2107         }
2108
2109         if (!param.subpart_name) {
2110                 ERROR("%s: -n option required\n", __func__);
2111                 return COMMAND_ERR;
2112         }
2113
2114         int type = find_type_by_name(param.subpart_name);
2115
2116         if (type == -1)
2117                 return COMMAND_ERR;
2118
2119         const struct subpart_info *curr_subpart = &subparts[type];
2120
2121         if (curr_subpart->attr & AUTO_GENERATED) {
2122                 ERROR("Cannot replace auto-generated sub-partitions.\n");
2123                 return COMMAND_ERR;
2124         }
2125
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);
2129                 return COMMAND_ERR;
2130         }
2131
2132         if (param.dir_ops)
2133                 return ifwi_dir_replace(type);
2134
2135         return ifwi_raw_replace(type);
2136 }
2137
2138 static enum ifwi_ret ifwi_create(void)
2139 {
2140         /*
2141          * Create peels off any non-IFWI content present in the input buffer and
2142          * creates output file with only the IFWI present.
2143          */
2144
2145         if (!param.file_name) {
2146                 ERROR("%s: -f option required\n", __func__);
2147                 return COMMAND_ERR;
2148         }
2149
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);
2157
2158         /*
2159          * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
2160          */
2161         ifwi_image.input_ifwi_end_offset -= ifwi_image.input_ifwi_start_offset;
2162         ifwi_image.input_ifwi_start_offset = 0;
2163
2164         param.image_name = param.file_name;
2165
2166         return REPACK_REQUIRED;
2167 }
2168
2169 struct command {
2170         const char *name;
2171         const char *optstring;
2172         enum ifwi_ret (*function)(void);
2173 };
2174
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},
2182 };
2183
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'},
2191         {NULL,              0,                 0,  0 }
2192 };
2193
2194 static void usage(const char *name)
2195 {
2196         printf("ifwitool: Utility for IFWI manipulation\n\n"
2197                "USAGE:\n"
2198                " %s [-h]\n"
2199                " %s FILE COMMAND [PARAMETERS]\n\n"
2200                "COMMANDs:\n"
2201                " add -f FILE -n NAME [-d -e ENTRY]\n"
2202                " create -f FILE\n"
2203                " delete -n NAME\n"
2204                " extract -f FILE -n NAME [-d -e ENTRY]\n"
2205                " print [-d]\n"
2206                " replace -f FILE -n NAME [-d -e ENTRY]\n"
2207                "OPTIONs:\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",
2214                name, name
2215                );
2216
2217         printf("\nNAME should be one of:\n");
2218         int i;
2219
2220         for (i = 0; i < MAX_SUBPARTS; i++)
2221                 printf("%s(%s)\n", subparts[i].name, subparts[i].readable_name);
2222         printf("\n");
2223 }
2224
2225 int main(int argc, char **argv)
2226 {
2227         if (argc < 3) {
2228                 usage(argv[0]);
2229                 return 1;
2230         }
2231
2232         param.image_name = argv[1];
2233         char *cmd = argv[2];
2234
2235         optind += 2;
2236
2237         uint32_t i;
2238
2239         for (i = 0; i < ARRAY_SIZE(commands); i++) {
2240                 if (strcmp(cmd, commands[i].name) != 0)
2241                         continue;
2242
2243                 int c;
2244
2245                 while (1) {
2246                         int option_index;
2247
2248                         c = getopt_long(argc, argv, commands[i].optstring,
2249                                         long_options, &option_index);
2250
2251                         if (c == -1)
2252                                 break;
2253
2254                         /* Filter out illegal long options */
2255                         if (!strchr(commands[i].optstring, c)) {
2256                                 ERROR("%s: invalid option -- '%c'\n", argv[0],
2257                                       c);
2258                                 c = '?';
2259                         }
2260
2261                         switch (c) {
2262                         case 'n':
2263                                 param.subpart_name = optarg;
2264                                 break;
2265                         case 'f':
2266                                 param.file_name = optarg;
2267                                 break;
2268                         case 'd':
2269                                 param.dir_ops = 1;
2270                                 break;
2271                         case 'e':
2272                                 param.dentry_name = optarg;
2273                                 break;
2274                         case 'v':
2275                                 verbose++;
2276                                 break;
2277                         case 'h':
2278                         case '?':
2279                                 usage(argv[0]);
2280                                 return 1;
2281                         default:
2282                                 break;
2283                         }
2284                 }
2285
2286                 if (ifwi_parse()) {
2287                         ERROR("%s: ifwi parsing failed\n", argv[0]);
2288                         return 1;
2289                 }
2290
2291                 enum ifwi_ret ret = commands[i].function();
2292
2293                 if (ret == COMMAND_ERR) {
2294                         ERROR("%s: failed execution\n", argv[0]);
2295                         return 1;
2296                 }
2297
2298                 if (ret == REPACK_REQUIRED)
2299                         ifwi_repack();
2300
2301                 return 0;
2302         }
2303
2304         ERROR("%s: invalid command\n", argv[0]);
2305         return 1;
2306 }