blob: 543e9d4e702665c0d105adcc6ee7a6112054fac0 [file] [log] [blame]
Simon Glassd7dbfce2019-07-08 13:18:20 -06001// 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
Bin Mengd198c702019-10-27 05:19:44 -070013#ifndef __packed
Simon Glassd7dbfce2019-07-08 13:18:20 -060014#define __packed __attribute__((packed))
Bin Mengd198c702019-10-27 05:19:44 -070015#endif
Simon Glassd7dbfce2019-07-08 13:18:20 -060016#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
38static int verbose = 1;
39
40/* Buffer and file I/O */
41struct 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 */
67static 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
75struct 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
94struct 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
106struct 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
112static 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 */
121struct 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 */
147struct 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
160struct 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
166static 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
171struct 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
196struct 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
207struct 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 */
231enum 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 */
240enum 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 */
273const 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
297const 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 */
322enum ifwi_ret {
323 COMMAND_ERR = -1,
324 NO_ACTION_REQUIRED = 0,
325 REPACK_REQUIRED = 1,
326};
327
328struct dir_ops {
329 enum ifwi_ret (*dir_add)(int type);
330};
331
332static enum ifwi_ret ibbp_dir_add(int type);
333
334const 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
391struct 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 */
405static 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
415static inline void *buffer_get(const struct buffer *b)
416{
417 return b->data;
418}
419
420static inline size_t buffer_size(const struct buffer *b)
421{
422 return b->size;
423}
424
425static 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 */
434static 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 */
444static 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 */
457static 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 */
465static 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
472int 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
486int 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
504void 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
519int 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
549static 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 */
559static inline uint8_t read_ble8(const void *src)
560{
561 const uint8_t *s = src;
562 return *s;
563}
564
565static 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
573static inline void write_ble8(void *dest, uint8_t val)
574{
575 *(uint8_t *)dest = val;
576}
577
578static 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
586static inline uint8_t read_at_le8(const void *src, size_t offset)
587{
588 return read_at_ble8(src, offset);
589}
590
591static inline void write_le8(void *dest, uint8_t val)
592{
593 write_ble8(dest, val);
594}
595
596static inline void write_at_le8(void *dest, uint8_t val, size_t offset)
597{
598 write_at_ble8(dest, val, offset);
599}
600
601static 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
608static 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
616static 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
622static 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
630static 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
638static 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
646static 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
652static 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
660static 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
670static 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
678static 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
684static 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 */
696static 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 */
724static 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
748static 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
781static 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
796static 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
823static 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
835static 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
856static 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 */
880static 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
896static 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 */
921static 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 */
945static 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 */
1009static 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
1041static 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
1056static 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
1075static 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
1096static void validate_subpart_dir_without_checksum(struct subpart_dir *s,
1097 const char *name)
1098{
1099 validate_subpart_dir(s, name, 0);
1100}
1101
1102static void validate_subpart_dir_with_checksum(struct subpart_dir *s,
1103 const char *name)
1104{
1105 validate_subpart_dir(s, name, 1);
1106}
1107
1108static 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 */
1159static 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 */
1221static 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
1251static 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 */
1288static 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
1324static 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 */
1345static 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 */
1435static 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 */
1467static 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 */
1483static 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 */
1574static 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
1591static 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
1604static 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
1617static 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
1641static 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
1651static 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
1681static 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
1722static 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
1767static 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
1777static 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
1803static 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
1839static 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
1869static 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
1918static 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
1929static 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
1965static 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
2001static 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
2007static 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
2102static 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
2138static 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
2169struct command {
2170 const char *name;
2171 const char *optstring;
2172 enum ifwi_ret (*function)(void);
2173};
2174
2175static 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
2184static 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
2194static 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
2225int 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}