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