1
2
3
4
5
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
21
22
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
36static int verbose = 1;
37
38
39struct 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
52
53
54
55
56
57
58
59
60
61
62#define BPDT_SIGNATURE (0x000055AA)
63
64
65static 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
73struct bpdt_header {
74
75
76
77
78 uint32_t signature;
79
80 uint16_t descriptor_count;
81
82 uint16_t bpdt_version;
83
84 uint32_t xor_redundant_block;
85
86 uint32_t ifwi_version;
87
88 uint64_t fit_tool_version;
89} __packed;
90#define BPDT_HEADER_SIZE (sizeof(struct bpdt_header))
91
92struct bpdt_entry {
93
94 uint16_t type;
95
96 uint16_t flags;
97
98 uint32_t offset;
99
100 uint32_t size;
101} __packed;
102#define BPDT_ENTRY_SIZE (sizeof(struct bpdt_entry))
103
104struct bpdt {
105 struct bpdt_header h;
106
107 struct bpdt_entry e[0];
108} __packed;
109
110static inline size_t get_bpdt_size(struct bpdt_header *h)
111{
112 return (sizeof(*h) + BPDT_ENTRY_SIZE * h->descriptor_count);
113}
114
115
116#define BPDT_MIN_SIZE ((size_t)512)
117
118
119struct subpart_dir_header {
120
121 uint32_t marker;
122
123 uint32_t num_entries;
124
125 uint8_t header_version;
126
127 uint8_t entry_version;
128
129 uint8_t header_length;
130
131
132
133
134 uint8_t checksum;
135
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
145struct subpart_dir_entry {
146
147 uint8_t name[12];
148
149 uint32_t offset;
150
151 uint32_t length;
152
153 uint32_t rsvd;
154} __packed;
155#define SUBPART_DIR_ENTRY_SIZE \
156 (sizeof(struct subpart_dir_entry))
157
158struct subpart_dir {
159 struct subpart_dir_header h;
160
161 struct subpart_dir_entry e[0];
162} __packed;
163
164static 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
169struct 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
194struct 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
205struct 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
221
222
223
224
225
226
227
228
229enum 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
238enum 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
263
264
265
266
267
268
269
270
271const enum bpdt_entry_type bpdt_header_order[MAX_SUBPARTS] = {
272
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
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
295const enum bpdt_entry_type bpdt_pack_order[MAX_SUBPARTS] = {
296
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
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
320enum ifwi_ret {
321 COMMAND_ERR = -1,
322 NO_ACTION_REQUIRED = 0,
323 REPACK_REQUIRED = 1,
324};
325
326struct dir_ops {
327 enum ifwi_ret (*dir_add)(int type);
328};
329
330static enum ifwi_ret ibbp_dir_add(int type);
331
332const 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
339 [SMIP_TYPE] = {"SMIP", "SMIP", CONTAINS_DIR, {NULL} },
340
341 [CSE_RBE_TYPE] = {"RBEP", "CSE_RBE", CONTAINS_DIR |
342 MANDATORY_BPDT_ENTRY, {NULL} },
343
344 [CSE_BUP_TYPE] = {"FTPR", "CSE_BUP", CONTAINS_DIR |
345 MANDATORY_BPDT_ENTRY, {NULL} },
346
347 [UCODE_TYPE] = {"UCOD", "Microcode", CONTAINS_DIR, {NULL} },
348
349 [IBB_TYPE] = {"IBBP", "Bootblock", CONTAINS_DIR, {ibbp_dir_add} },
350
351 [S_BPDT_TYPE] = {"S_BPDT", "S-BPDT", AUTO_GENERATED |
352 MANDATORY_BPDT_ENTRY, {NULL} },
353
354 [OBB_TYPE] = {"OBBP", "OEM boot block", CONTAINS_DIR |
355 NON_CRITICAL_SUBPART, {NULL} },
356
357 [CSE_MAIN_TYPE] = {"NFTP", "CSE_MAIN", CONTAINS_DIR |
358 NON_CRITICAL_SUBPART, {NULL} },
359
360 [ISH_TYPE] = {"ISHP", "ISH", NON_CRITICAL_SUBPART, {NULL} },
361
362 [CSE_IDLM_TYPE] = {"DLMP", "CSE_IDLM", CONTAINS_DIR |
363 MANDATORY_BPDT_ENTRY, {NULL} },
364
365 [IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
366 LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
367 {NULL} },
368
369 [DEBUG_TOKENS_TYPE] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL} },
370
371 [UFS_PHY_TYPE] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K |
372 MANDATORY_BPDT_ENTRY, {NULL} },
373
374 [UFS_GPP_TYPE] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K |
375 MANDATORY_BPDT_ENTRY, {NULL} },
376
377 [PMC_TYPE] = {"PMCP", "PMC firmware", CONTAINS_DIR, {NULL} },
378
379 [IUNIT_TYPE] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART, {NULL} },
380
381 [NVM_CONFIG_TYPE] = {"NVM_CONFIG", "NVM Config", 0, {NULL} },
382
383 [UEP_TYPE] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
384 {NULL} },
385
386 [UFS_RATE_B_TYPE] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL} },
387};
388
389struct ifwi_image {
390
391 struct buffer input_buff;
392
393
394 struct buffer bpdt;
395 size_t input_ifwi_start_offset;
396 size_t input_ifwi_end_offset;
397
398
399 struct buffer subpart_buf[MAX_SUBPARTS];
400} ifwi_image;
401
402
403static 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
413static inline void *buffer_get(const struct buffer *b)
414{
415 return b->data;
416}
417
418static inline size_t buffer_size(const struct buffer *b)
419{
420 return b->size;
421}
422
423static inline size_t buffer_offset(const struct buffer *b)
424{
425 return b->offset;
426}
427
428
429
430
431
432static inline void buffer_set_size(struct buffer *b, size_t size)
433{
434 b->size = size;
435}
436
437
438
439
440
441
442static 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
453
454
455static 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
463static 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
470int 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
484int 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
502void 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
517int 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
547static 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
557static inline uint8_t read_ble8(const void *src)
558{
559 const uint8_t *s = src;
560 return *s;
561}
562
563static 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
571static inline void write_ble8(void *dest, uint8_t val)
572{
573 *(uint8_t *)dest = val;
574}
575
576static 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
584static inline uint8_t read_at_le8(const void *src, size_t offset)
585{
586 return read_at_ble8(src, offset);
587}
588
589static inline void write_le8(void *dest, uint8_t val)
590{
591 write_ble8(dest, val);
592}
593
594static inline void write_at_le8(void *dest, uint8_t val, size_t offset)
595{
596 write_at_ble8(dest, val, offset);
597}
598
599static 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
606static 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
614static 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
620static 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
628static 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
636static 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
644static 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
650static 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
658static 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
668static 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
676static 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
682static 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
692
693
694static 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
720
721
722static size_t fix_member(void *data, size_t offset, size_t size_bytes)
723{
724 uint8_t *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
746static 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
779static 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
794static 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
821static 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
833static 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
854static 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
876
877
878static 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
894static 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
917
918
919static 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
939
940
941
942
943static 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
974
975
976
977 if ((e[i].offset + e[i].size) > max_offset)
978 max_offset = e[i].offset + e[i].size;
979
980
981
982
983
984
985
986
987
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
1005
1006
1007static 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
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
1024
1025
1026 if (bpdt->h.descriptor_count == 0)
1027 return (offset + BPDT_HEADER_SIZE);
1028
1029
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
1035 return read_subpart_buf(data, size, &bpdt->e[0],
1036 bpdt->h.descriptor_count);
1037}
1038
1039static 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
1054static 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
1070 return -checksum;
1071}
1072
1073static 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
1094static void validate_subpart_dir_without_checksum(struct subpart_dir *s,
1095 const char *name)
1096{
1097 validate_subpart_dir(s, name, 0);
1098}
1099
1100static void validate_subpart_dir_with_checksum(struct subpart_dir *s,
1101 const char *name)
1102{
1103 validate_subpart_dir(s, name, 1);
1104}
1105
1106static 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
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
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
1157static 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
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
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
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
1200 parse_sbpdt(data, ifwi_size);
1201
1202
1203
1204
1205
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
1215
1216
1217
1218
1219static 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
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
1242 memset(ptr, 0, entries_size);
1243
1244 memset(ptr + entries_size, 0xFF, size - bpdt_size);
1245
1246 bpdt->h.descriptor_count = count;
1247}
1248
1249static void bpdt_reset(void)
1250{
1251 size_t i;
1252 size_t bpdt_count = 0, sbpdt_count = 0, dummy_bpdt_count = 0;
1253
1254
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
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
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
1286static 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
1322static 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
1343static 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
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
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
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
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
1421
1422
1423
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
1433static 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(&h->signature, offset, sizeof(h->signature));
1445 offset = fix_member(&h->descriptor_count, offset,
1446 sizeof(h->descriptor_count));
1447 offset = fix_member(&h->bpdt_version, offset, sizeof(h->bpdt_version));
1448 offset = fix_member(&h->xor_redundant_block, offset,
1449 sizeof(h->xor_redundant_block));
1450 offset = fix_member(&h->ifwi_version, offset, sizeof(h->ifwi_version));
1451 offset = fix_member(&h->fit_tool_version, offset,
1452 sizeof(h->fit_tool_version));
1453
1454 uint32_t i;
1455
1456 for (i = 0; i < count; i++) {
1457 offset = fix_member(&e[i].type, offset, sizeof(e[i].type));
1458 offset = fix_member(&e[i].flags, offset, sizeof(e[i].flags));
1459 offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
1460 offset = fix_member(&e[i].size, offset, sizeof(e[i].size));
1461 }
1462}
1463
1464
1465static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src)
1466{
1467 bpdt_fixup_write_buffer(src);
1468 memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src));
1469}
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481static void ifwi_write(const char *image_name)
1482{
1483 struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE);
1484
1485 assert(s);
1486
1487 size_t ifwi_start, ifwi_end, file_end;
1488
1489 ifwi_start = ifwi_image.input_ifwi_start_offset;
1490 ifwi_end = ifwi_start + ALIGN(s->offset + s->size, 4 * KiB);
1491 file_end = ifwi_end + (buffer_size(&ifwi_image.input_buff) -
1492 ifwi_image.input_ifwi_end_offset);
1493
1494 struct buffer b;
1495
1496 alloc_buffer(&b, file_end, "Final-IFWI");
1497
1498 uint8_t *input_data = buffer_get(&ifwi_image.input_buff);
1499 uint8_t *output_data = buffer_get(&b);
1500
1501 DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start,
1502 ifwi_end, file_end);
1503
1504
1505 memcpy(output_data, input_data, ifwi_start);
1506
1507 DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start);
1508
1509 struct buffer ifwi;
1510
1511 buffer_splice(&ifwi, &b, ifwi_start, ifwi_end - ifwi_start);
1512 uint8_t *ifwi_data = buffer_get(&ifwi);
1513
1514
1515 struct bpdt_entry *curr;
1516 struct buffer *subpart_buf;
1517 int i, type;
1518
1519 for (i = 0; i < MAX_SUBPARTS; i++) {
1520 type = bpdt_pack_order[i];
1521
1522 if (type == S_BPDT_TYPE)
1523 continue;
1524
1525 curr = find_entry_by_type(type);
1526
1527 if (!curr || !curr->size)
1528 continue;
1529
1530 subpart_buf = &ifwi_image.subpart_buf[type];
1531
1532 DEBUG("curr->offset=0x%x, curr->size=0x%x, type=%d, write_size=0x%zx\n",
1533 curr->offset, curr->size, type, buffer_size(subpart_buf));
1534
1535 assert((curr->offset + buffer_size(subpart_buf)) <=
1536 buffer_size(&ifwi));
1537
1538 memcpy(ifwi_data + curr->offset, buffer_get(subpart_buf),
1539 buffer_size(subpart_buf));
1540 }
1541
1542
1543 if (ifwi_end != file_end) {
1544 memcpy(output_data + ifwi_end,
1545 input_data + ifwi_image.input_ifwi_end_offset,
1546 file_end - ifwi_end);
1547 DEBUG("Copied non-IFWI suffix (offset=0x%zx,size=0x%zx).\n",
1548 ifwi_end, file_end - ifwi_end);
1549 }
1550
1551
1552
1553
1554
1555 bpdt_write(&ifwi, s->offset, &ifwi_image.subpart_buf[S_BPDT_TYPE]);
1556 bpdt_write(&ifwi, 0, &ifwi_image.bpdt);
1557
1558 if (buffer_write_file(&b, image_name)) {
1559 ERROR("File write error\n");
1560 exit(-1);
1561 }
1562
1563 buffer_delete(&b);
1564 printf("Image written successfully to %s.\n", image_name);
1565}
1566
1567
1568
1569
1570
1571
1572static void ifwi_repack(void)
1573{
1574 bpdt_reset();
1575 bpdt_entries_init_header_order();
1576 bpdt_entries_init_pack_order();
1577
1578 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1579
1580 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1581
1582 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1583 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1584
1585 DEBUG("Repack done.. writing image.\n");
1586 ifwi_write(param.image_name);
1587}
1588
1589static void init_subpart_dir_header(struct subpart_dir_header *hdr,
1590 size_t count, const char *name)
1591{
1592 memset(hdr, 0, sizeof(*hdr));
1593
1594 hdr->marker = SUBPART_DIR_MARKER;
1595 hdr->num_entries = count;
1596 hdr->header_version = SUBPART_DIR_HEADER_VERSION_SUPPORTED;
1597 hdr->entry_version = SUBPART_DIR_ENTRY_VERSION_SUPPORTED;
1598 hdr->header_length = SUBPART_DIR_HEADER_SIZE;
1599 memcpy(hdr->name, name, sizeof(hdr->name));
1600}
1601
1602static size_t init_subpart_dir_entry(struct subpart_dir_entry *e,
1603 struct buffer *b, size_t offset)
1604{
1605 memset(e, 0, sizeof(*e));
1606
1607 assert(strlen(b->name) <= sizeof(e->name));
1608 strncpy((char *)e->name, (char *)b->name, sizeof(e->name));
1609 e->offset = offset;
1610 e->length = buffer_size(b);
1611
1612 return (offset + buffer_size(b));
1613}
1614
1615static void init_manifest_header(struct manifest_header *hdr, size_t size)
1616{
1617 memset(hdr, 0, sizeof(*hdr));
1618
1619 hdr->header_type = 0x4;
1620 assert((MANIFEST_HDR_SIZE % DWORD_SIZE) == 0);
1621 hdr->header_length = MANIFEST_HDR_SIZE / DWORD_SIZE;
1622 hdr->header_version = 0x10000;
1623 hdr->vendor = 0x8086;
1624
1625 struct tm *local_time;
1626 time_t curr_time;
1627 char buffer[11];
1628
1629 curr_time = time(NULL);
1630 local_time = localtime(&curr_time);
1631 strftime(buffer, sizeof(buffer), "0x%Y%m%d", local_time);
1632 hdr->date = strtoul(buffer, NULL, 16);
1633
1634 assert((size % DWORD_SIZE) == 0);
1635 hdr->size = size / DWORD_SIZE;
1636 hdr->id = MANIFEST_ID_MAGIC;
1637}
1638
1639static void init_signed_pkg_info_ext(struct signed_pkg_info_ext *ext,
1640 size_t count, const char *name)
1641{
1642 memset(ext, 0, sizeof(*ext));
1643
1644 ext->ext_type = SIGNED_PKG_INFO_EXT_TYPE;
1645 ext->ext_length = SIGNED_PKG_INFO_EXT_SIZE + count * MODULE_SIZE;
1646 memcpy(ext->name, name, sizeof(ext->name));
1647}
1648
1649static void subpart_dir_fixup_write_buffer(struct buffer *buf)
1650{
1651 struct subpart_dir *s = buffer_get(buf);
1652 struct subpart_dir_header *h = &s->h;
1653 struct subpart_dir_entry *e = &s->e[0];
1654
1655 size_t count = h->num_entries;
1656 size_t offset = 0;
1657
1658 offset = fix_member(&h->marker, offset, sizeof(h->marker));
1659 offset = fix_member(&h->num_entries, offset, sizeof(h->num_entries));
1660 offset = fix_member(&h->header_version, offset,
1661 sizeof(h->header_version));
1662 offset = fix_member(&h->entry_version, offset,
1663 sizeof(h->entry_version));
1664 offset = fix_member(&h->header_length, offset,
1665 sizeof(h->header_length));
1666 offset = fix_member(&h->checksum, offset, sizeof(h->checksum));
1667 offset += sizeof(h->name);
1668
1669 uint32_t i;
1670
1671 for (i = 0; i < count; i++) {
1672 offset += sizeof(e[i].name);
1673 offset = fix_member(&e[i].offset, offset, sizeof(e[i].offset));
1674 offset = fix_member(&e[i].length, offset, sizeof(e[i].length));
1675 offset = fix_member(&e[i].rsvd, offset, sizeof(e[i].rsvd));
1676 }
1677}
1678
1679static void create_subpart(struct buffer *dst, struct buffer *info[],
1680 size_t count, const char *name)
1681{
1682 struct buffer subpart_dir_buff;
1683 size_t size = SUBPART_DIR_HEADER_SIZE + count * SUBPART_DIR_ENTRY_SIZE;
1684
1685 alloc_buffer(&subpart_dir_buff, size, "subpart-dir");
1686
1687 struct subpart_dir_header *h = buffer_get(&subpart_dir_buff);
1688 struct subpart_dir_entry *e = (struct subpart_dir_entry *)(h + 1);
1689
1690 init_subpart_dir_header(h, count, name);
1691
1692 size_t curr_offset = size;
1693 size_t i;
1694
1695 for (i = 0; i < count; i++) {
1696 curr_offset = init_subpart_dir_entry(&e[i], info[i],
1697 curr_offset);
1698 }
1699
1700 alloc_buffer(dst, curr_offset, name);
1701 uint8_t *data = buffer_get(dst);
1702
1703 for (i = 0; i < count; i++) {
1704 memcpy(data + e[i].offset, buffer_get(info[i]),
1705 buffer_size(info[i]));
1706 }
1707
1708 h->checksum = calc_checksum(buffer_get(&subpart_dir_buff));
1709
1710 struct subpart_dir *dir = buffer_get(&subpart_dir_buff);
1711
1712 print_subpart_dir(dir);
1713
1714 subpart_dir_fixup_write_buffer(&subpart_dir_buff);
1715 memcpy(data, dir, buffer_size(&subpart_dir_buff));
1716
1717 buffer_delete(&subpart_dir_buff);
1718}
1719
1720static enum ifwi_ret ibbp_dir_add(int type)
1721{
1722 struct buffer manifest;
1723 struct signed_pkg_info_ext *ext;
1724 struct buffer ibbl;
1725 struct buffer ibb;
1726
1727#define DUMMY_IBB_SIZE (4 * KiB)
1728
1729 assert(type == IBB_TYPE);
1730
1731
1732
1733
1734
1735 size_t size = MANIFEST_HDR_SIZE + SIGNED_PKG_INFO_EXT_SIZE;
1736
1737 alloc_buffer(&manifest, size, "IBBP.man");
1738
1739 struct manifest_header *man_hdr = buffer_get(&manifest);
1740
1741 init_manifest_header(man_hdr, size);
1742
1743 ext = (struct signed_pkg_info_ext *)(man_hdr + 1);
1744
1745 init_signed_pkg_info_ext(ext, 0, subparts[type].name);
1746
1747
1748 if (buffer_from_file(&ibbl, param.file_name))
1749 return COMMAND_ERR;
1750
1751
1752 alloc_buffer(&ibb, DUMMY_IBB_SIZE, "IBB");
1753 memset(buffer_get(&ibb), 0xFF, DUMMY_IBB_SIZE);
1754
1755
1756 struct buffer *info[] = {
1757 &manifest, &ibbl, &ibb,
1758 };
1759 create_subpart(&ifwi_image.subpart_buf[type], &info[0],
1760 ARRAY_SIZE(info), subparts[type].name);
1761
1762 return REPACK_REQUIRED;
1763}
1764
1765static enum ifwi_ret ifwi_raw_add(int type)
1766{
1767 if (buffer_from_file(&ifwi_image.subpart_buf[type], param.file_name))
1768 return COMMAND_ERR;
1769
1770 printf("Sub-partition %s(%d) added from file %s.\n", param.subpart_name,
1771 type, param.file_name);
1772 return REPACK_REQUIRED;
1773}
1774
1775static enum ifwi_ret ifwi_dir_add(int type)
1776{
1777 if (!(subparts[type].attr & CONTAINS_DIR) ||
1778 !subparts[type].dir_ops.dir_add) {
1779 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1780 subparts[type].name, type);
1781 return COMMAND_ERR;
1782 }
1783
1784 if (!param.dentry_name) {
1785 ERROR("%s: -e option required\n", __func__);
1786 return COMMAND_ERR;
1787 }
1788
1789 enum ifwi_ret ret = subparts[type].dir_ops.dir_add(type);
1790
1791 if (ret != COMMAND_ERR)
1792 printf("Sub-partition %s(%d) entry %s added from file %s.\n",
1793 param.subpart_name, type, param.dentry_name,
1794 param.file_name);
1795 else
1796 ERROR("Sub-partition dir operation failed.\n");
1797
1798 return ret;
1799}
1800
1801static enum ifwi_ret ifwi_add(void)
1802{
1803 if (!param.file_name) {
1804 ERROR("%s: -f option required\n", __func__);
1805 return COMMAND_ERR;
1806 }
1807
1808 if (!param.subpart_name) {
1809 ERROR("%s: -n option required\n", __func__);
1810 return COMMAND_ERR;
1811 }
1812
1813 int type = find_type_by_name(param.subpart_name);
1814
1815 if (type == -1)
1816 return COMMAND_ERR;
1817
1818 const struct subpart_info *curr_subpart = &subparts[type];
1819
1820 if (curr_subpart->attr & AUTO_GENERATED) {
1821 ERROR("Cannot add auto-generated sub-partitions.\n");
1822 return COMMAND_ERR;
1823 }
1824
1825 if (buffer_size(&ifwi_image.subpart_buf[type])) {
1826 ERROR("Image already contains sub-partition %s(%d).\n",
1827 param.subpart_name, type);
1828 return COMMAND_ERR;
1829 }
1830
1831 if (param.dir_ops)
1832 return ifwi_dir_add(type);
1833
1834 return ifwi_raw_add(type);
1835}
1836
1837static enum ifwi_ret ifwi_delete(void)
1838{
1839 if (!param.subpart_name) {
1840 ERROR("%s: -n option required\n", __func__);
1841 return COMMAND_ERR;
1842 }
1843
1844 int type = find_type_by_name(param.subpart_name);
1845
1846 if (type == -1)
1847 return COMMAND_ERR;
1848
1849 const struct subpart_info *curr_subpart = &subparts[type];
1850
1851 if (curr_subpart->attr & AUTO_GENERATED) {
1852 ERROR("Cannot delete auto-generated sub-partitions.\n");
1853 return COMMAND_ERR;
1854 }
1855
1856 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1857 printf("Image does not contain sub-partition %s(%d).\n",
1858 param.subpart_name, type);
1859 return NO_ACTION_REQUIRED;
1860 }
1861
1862 buffer_delete(&ifwi_image.subpart_buf[type]);
1863 printf("Sub-Partition %s(%d) deleted.\n", subparts[type].name, type);
1864 return REPACK_REQUIRED;
1865}
1866
1867static enum ifwi_ret ifwi_dir_extract(int type)
1868{
1869 if (!(subparts[type].attr & CONTAINS_DIR)) {
1870 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1871 subparts[type].name, type);
1872 return COMMAND_ERR;
1873 }
1874
1875 if (!param.dentry_name) {
1876 ERROR("%s: -e option required.\n", __func__);
1877 return COMMAND_ERR;
1878 }
1879
1880 struct buffer subpart_dir_buff;
1881
1882 parse_subpart_dir(&subpart_dir_buff, &ifwi_image.subpart_buf[type],
1883 subparts[type].name);
1884
1885 uint32_t i;
1886 struct subpart_dir *s = buffer_get(&subpart_dir_buff);
1887
1888 for (i = 0; i < s->h.num_entries; i++) {
1889 if (!strncmp((char *)s->e[i].name, param.dentry_name,
1890 sizeof(s->e[i].name)))
1891 break;
1892 }
1893
1894 if (i == s->h.num_entries) {
1895 ERROR("Entry %s not found in subpartition for %s.\n",
1896 param.dentry_name, param.subpart_name);
1897 exit(-1);
1898 }
1899
1900 struct buffer dst;
1901
1902 DEBUG("Splicing buffer at 0x%x size 0x%x\n", s->e[i].offset,
1903 s->e[i].length);
1904 buffer_splice(&dst, &ifwi_image.subpart_buf[type], s->e[i].offset,
1905 s->e[i].length);
1906
1907 if (buffer_write_file(&dst, param.file_name))
1908 return COMMAND_ERR;
1909
1910 printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1911 param.subpart_name, type, param.dentry_name, param.file_name);
1912
1913 return NO_ACTION_REQUIRED;
1914}
1915
1916static enum ifwi_ret ifwi_raw_extract(int type)
1917{
1918 if (buffer_write_file(&ifwi_image.subpart_buf[type], param.file_name))
1919 return COMMAND_ERR;
1920
1921 printf("Sub-Partition %s(%d) stored in %s.\n", param.subpart_name, type,
1922 param.file_name);
1923
1924 return NO_ACTION_REQUIRED;
1925}
1926
1927static enum ifwi_ret ifwi_extract(void)
1928{
1929 if (!param.file_name) {
1930 ERROR("%s: -f option required\n", __func__);
1931 return COMMAND_ERR;
1932 }
1933
1934 if (!param.subpart_name) {
1935 ERROR("%s: -n option required\n", __func__);
1936 return COMMAND_ERR;
1937 }
1938
1939 int type = find_type_by_name(param.subpart_name);
1940
1941 if (type == -1)
1942 return COMMAND_ERR;
1943
1944 if (type == S_BPDT_TYPE) {
1945 INFO("Tool does not support raw extract for %s\n",
1946 param.subpart_name);
1947 return NO_ACTION_REQUIRED;
1948 }
1949
1950 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1951 ERROR("Image does not contain sub-partition %s(%d).\n",
1952 param.subpart_name, type);
1953 return COMMAND_ERR;
1954 }
1955
1956 INFO("Extracting sub-partition %s(%d).\n", param.subpart_name, type);
1957 if (param.dir_ops)
1958 return ifwi_dir_extract(type);
1959
1960 return ifwi_raw_extract(type);
1961}
1962
1963static enum ifwi_ret ifwi_print(void)
1964{
1965 verbose += 2;
1966
1967 struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1968
1969 bpdt_print_header(&b->h, "BPDT");
1970 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1971
1972 b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1973 bpdt_print_header(&b->h, "S-BPDT");
1974 bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1975
1976 if (param.dir_ops == 0) {
1977 verbose -= 2;
1978 return NO_ACTION_REQUIRED;
1979 }
1980
1981 int i;
1982 struct buffer subpart_dir_buf;
1983
1984 for (i = 0; i < MAX_SUBPARTS ; i++) {
1985 if (!(subparts[i].attr & CONTAINS_DIR) ||
1986 (buffer_size(&ifwi_image.subpart_buf[i]) == 0))
1987 continue;
1988
1989 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[i],
1990 subparts[i].name);
1991 buffer_delete(&subpart_dir_buf);
1992 }
1993
1994 verbose -= 2;
1995
1996 return NO_ACTION_REQUIRED;
1997}
1998
1999static enum ifwi_ret ifwi_raw_replace(int type)
2000{
2001 buffer_delete(&ifwi_image.subpart_buf[type]);
2002 return ifwi_raw_add(type);
2003}
2004
2005static enum ifwi_ret ifwi_dir_replace(int type)
2006{
2007 if (!(subparts[type].attr & CONTAINS_DIR)) {
2008 ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
2009 subparts[type].name, type);
2010 return COMMAND_ERR;
2011 }
2012
2013 if (!param.dentry_name) {
2014 ERROR("%s: -e option required.\n", __func__);
2015 return COMMAND_ERR;
2016 }
2017
2018 struct buffer subpart_dir_buf;
2019
2020 parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[type],
2021 subparts[type].name);
2022
2023 uint32_t i;
2024 struct subpart_dir *s = buffer_get(&subpart_dir_buf);
2025
2026 for (i = 0; i < s->h.num_entries; i++) {
2027 if (!strcmp((char *)s->e[i].name, param.dentry_name))
2028 break;
2029 }
2030
2031 if (i == s->h.num_entries) {
2032 ERROR("Entry %s not found in subpartition for %s.\n",
2033 param.dentry_name, param.subpart_name);
2034 exit(-1);
2035 }
2036
2037 struct buffer b;
2038
2039 if (buffer_from_file(&b, param.file_name)) {
2040 ERROR("Failed to read %s\n", param.file_name);
2041 exit(-1);
2042 }
2043
2044 struct buffer dst;
2045 size_t dst_size = buffer_size(&ifwi_image.subpart_buf[type]) +
2046 buffer_size(&b) - s->e[i].length;
2047 size_t subpart_start = s->e[i].offset;
2048 size_t subpart_end = s->e[i].offset + s->e[i].length;
2049
2050 alloc_buffer(&dst, dst_size, ifwi_image.subpart_buf[type].name);
2051
2052 uint8_t *src_data = buffer_get(&ifwi_image.subpart_buf[type]);
2053 uint8_t *dst_data = buffer_get(&dst);
2054 size_t curr_offset = 0;
2055
2056
2057 memcpy(dst_data + curr_offset, src_data, subpart_start);
2058 curr_offset += subpart_start;
2059
2060
2061 memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
2062 curr_offset += buffer_size(&b);
2063
2064
2065 memcpy(dst_data + curr_offset, src_data + subpart_end,
2066 buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end);
2067
2068
2069 int offset = s->e[i].offset;
2070
2071 buffer_delete(&ifwi_image.subpart_buf[type]);
2072 ifwi_image.subpart_buf[type] = dst;
2073
2074
2075 s->e[i].length = buffer_size(&b);
2076 buffer_delete(&b);
2077
2078
2079 offset = s->e[i].offset - offset;
2080 for (; i < s->h.num_entries; i++)
2081 s->e[i].offset += offset;
2082
2083
2084 s->h.checksum = calc_checksum(s);
2085
2086
2087 subpart_dir_fixup_write_buffer(&subpart_dir_buf);
2088
2089 memcpy(dst_data, buffer_get(&subpart_dir_buf),
2090 buffer_size(&subpart_dir_buf));
2091
2092 buffer_delete(&subpart_dir_buf);
2093
2094 printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
2095 param.subpart_name, type, param.dentry_name, param.file_name);
2096
2097 return REPACK_REQUIRED;
2098}
2099
2100static enum ifwi_ret ifwi_replace(void)
2101{
2102 if (!param.file_name) {
2103 ERROR("%s: -f option required\n", __func__);
2104 return COMMAND_ERR;
2105 }
2106
2107 if (!param.subpart_name) {
2108 ERROR("%s: -n option required\n", __func__);
2109 return COMMAND_ERR;
2110 }
2111
2112 int type = find_type_by_name(param.subpart_name);
2113
2114 if (type == -1)
2115 return COMMAND_ERR;
2116
2117 const struct subpart_info *curr_subpart = &subparts[type];
2118
2119 if (curr_subpart->attr & AUTO_GENERATED) {
2120 ERROR("Cannot replace auto-generated sub-partitions.\n");
2121 return COMMAND_ERR;
2122 }
2123
2124 if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
2125 ERROR("Image does not contain sub-partition %s(%d).\n",
2126 param.subpart_name, type);
2127 return COMMAND_ERR;
2128 }
2129
2130 if (param.dir_ops)
2131 return ifwi_dir_replace(type);
2132
2133 return ifwi_raw_replace(type);
2134}
2135
2136static enum ifwi_ret ifwi_create(void)
2137{
2138
2139
2140
2141
2142
2143 if (!param.file_name) {
2144 ERROR("%s: -f option required\n", __func__);
2145 return COMMAND_ERR;
2146 }
2147
2148
2149 buffer_seek(&ifwi_image.input_buff,
2150 ifwi_image.input_ifwi_start_offset);
2151
2152 buffer_set_size(&ifwi_image.input_buff,
2153 ifwi_image.input_ifwi_end_offset -
2154 ifwi_image.input_ifwi_start_offset);
2155
2156
2157
2158
2159 ifwi_image.input_ifwi_end_offset -= ifwi_image.input_ifwi_start_offset;
2160 ifwi_image.input_ifwi_start_offset = 0;
2161
2162 param.image_name = param.file_name;
2163
2164 return REPACK_REQUIRED;
2165}
2166
2167struct command {
2168 const char *name;
2169 const char *optstring;
2170 enum ifwi_ret (*function)(void);
2171};
2172
2173static const struct command commands[] = {
2174 {"add", "f:n:e:dvh?", ifwi_add},
2175 {"create", "f:vh?", ifwi_create},
2176 {"delete", "f:n:vh?", ifwi_delete},
2177 {"extract", "f:n:e:dvh?", ifwi_extract},
2178 {"print", "dh?", ifwi_print},
2179 {"replace", "f:n:e:dvh?", ifwi_replace},
2180};
2181
2182static struct option long_options[] = {
2183 {"subpart_dentry", required_argument, 0, 'e'},
2184 {"file", required_argument, 0, 'f'},
2185 {"help", required_argument, 0, 'h'},
2186 {"name", required_argument, 0, 'n'},
2187 {"dir_ops", no_argument, 0, 'd'},
2188 {"verbose", no_argument, 0, 'v'},
2189 {NULL, 0, 0, 0 }
2190};
2191
2192static void usage(const char *name)
2193{
2194 printf("ifwitool: Utility for IFWI manipulation\n\n"
2195 "USAGE:\n"
2196 " %s [-h]\n"
2197 " %s FILE COMMAND [PARAMETERS]\n\n"
2198 "COMMANDs:\n"
2199 " add -f FILE -n NAME [-d -e ENTRY]\n"
2200 " create -f FILE\n"
2201 " delete -n NAME\n"
2202 " extract -f FILE -n NAME [-d -e ENTRY]\n"
2203 " print [-d]\n"
2204 " replace -f FILE -n NAME [-d -e ENTRY]\n"
2205 "OPTIONs:\n"
2206 " -f FILE : File to read/write/create/extract\n"
2207 " -d : Perform directory operation\n"
2208 " -e ENTRY: Name of directory entry to operate on\n"
2209 " -v : Verbose level\n"
2210 " -h : Help message\n"
2211 " -n NAME : Name of sub-partition to operate on\n",
2212 name, name
2213 );
2214
2215 printf("\nNAME should be one of:\n");
2216 int i;
2217
2218 for (i = 0; i < MAX_SUBPARTS; i++)
2219 printf("%s(%s)\n", subparts[i].name, subparts[i].readable_name);
2220 printf("\n");
2221}
2222
2223int main(int argc, char **argv)
2224{
2225 if (argc < 3) {
2226 usage(argv[0]);
2227 return 1;
2228 }
2229
2230 param.image_name = argv[1];
2231 char *cmd = argv[2];
2232
2233 optind += 2;
2234
2235 uint32_t i;
2236
2237 for (i = 0; i < ARRAY_SIZE(commands); i++) {
2238 if (strcmp(cmd, commands[i].name) != 0)
2239 continue;
2240
2241 int c;
2242
2243 while (1) {
2244 int option_index;
2245
2246 c = getopt_long(argc, argv, commands[i].optstring,
2247 long_options, &option_index);
2248
2249 if (c == -1)
2250 break;
2251
2252
2253 if (!strchr(commands[i].optstring, c)) {
2254 ERROR("%s: invalid option -- '%c'\n", argv[0],
2255 c);
2256 c = '?';
2257 }
2258
2259 switch (c) {
2260 case 'n':
2261 param.subpart_name = optarg;
2262 break;
2263 case 'f':
2264 param.file_name = optarg;
2265 break;
2266 case 'd':
2267 param.dir_ops = 1;
2268 break;
2269 case 'e':
2270 param.dentry_name = optarg;
2271 break;
2272 case 'v':
2273 verbose++;
2274 break;
2275 case 'h':
2276 case '?':
2277 usage(argv[0]);
2278 return 1;
2279 default:
2280 break;
2281 }
2282 }
2283
2284 if (ifwi_parse()) {
2285 ERROR("%s: ifwi parsing failed\n", argv[0]);
2286 return 1;
2287 }
2288
2289 enum ifwi_ret ret = commands[i].function();
2290
2291 if (ret == COMMAND_ERR) {
2292 ERROR("%s: failed execution\n", argv[0]);
2293 return 1;
2294 }
2295
2296 if (ret == REPACK_REQUIRED)
2297 ifwi_repack();
2298
2299 return 0;
2300 }
2301
2302 ERROR("%s: invalid command\n", argv[0]);
2303 return 1;
2304}
2305