1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ifwitool, CLI utility for Integrated Firmware Image (IFWI) manipulation
4 *
5 * This is taken from the Coreboot project
6 */
7
8#include <assert.h>
9#include <stdbool.h>
10#include <getopt.h>
11#include "imagetool.h"
12#include "os_support.h"
13
14#ifndef __packed
15#define __packed		__attribute__((packed))
16#endif
17#define KiB			1024
18
19/*
20 * min()/max()/clamp() macros that also do
21 * strict type-checking.. See the
22 * "unnecessary" pointer comparison.
23 */
24#define min(x, y) ({				\
25	typeof(x) _min1 = (x);			\
26	typeof(y) _min2 = (y);			\
27	(void)&_min1 == &_min2);		\
28	_min1 < _min2 ? _min1 : _min2; })
29
30#define max(x, y) ({				\
31	typeof(x) _max1 = (x);			\
32	typeof(y) _max2 = (y);			\
33	(void)(&_max1 == &_max2);		\
34	_max1 > _max2 ? _max1 : _max2; })
35
36static int verbose = 1;
37
38/* Buffer and file I/O */
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 * BPDT is Boot Partition Descriptor Table. It is located at the start of a
52 * logical boot partition(LBP). It stores information about the critical
53 * sub-partitions present within the LBP.
54 *
55 * S-BPDT is Secondary Boot Partition Descriptor Table. It is located after the
56 * critical sub-partitions and contains information about the non-critical
57 * sub-partitions present within the LBP.
58 *
59 * Both tables are identified by BPDT_SIGNATURE stored at the start of the
60 * table.
61 */
62#define BPDT_SIGNATURE				(0x000055AA)
63
64/* Parameters passed in by caller */
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	 * This is used to identify start of BPDT. It should always be
76	 * BPDT_SIGNATURE.
77	 */
78	uint32_t signature;
79	/* Count of BPDT entries present */
80	uint16_t descriptor_count;
81	/* Version - Currently supported = 1 */
82	uint16_t bpdt_version;
83	/* Unused - Should be 0 */
84	uint32_t xor_redundant_block;
85	/* Version of IFWI build */
86	uint32_t ifwi_version;
87	/* Version of FIT tool used to create IFWI */
88	uint64_t fit_tool_version;
89} __packed;
90#define BPDT_HEADER_SIZE			(sizeof(struct bpdt_header))
91
92struct bpdt_entry {
93	/* Type of sub-partition */
94	uint16_t type;
95	/* Attributes of sub-partition */
96	uint16_t flags;
97	/* Offset of sub-partition from beginning of LBP */
98	uint32_t offset;
99	/* Size in bytes of sub-partition */
100	uint32_t size;
101} __packed;
102#define BPDT_ENTRY_SIZE			(sizeof(struct bpdt_entry))
103
104struct bpdt {
105	struct bpdt_header h;
106	/* In practice, this could be an array of 0 to n entries */
107	struct bpdt_entry e[0];
108} __packed;
109
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/* Minimum size in bytes allocated to BPDT in IFWI */
116#define BPDT_MIN_SIZE			((size_t)512)
117
118/* Header to define directory header for sub-partition */
119struct subpart_dir_header {
120	/* Should be SUBPART_DIR_MARKER */
121	uint32_t marker;
122	/* Number of directory entries in the sub-partition */
123	uint32_t num_entries;
124	/* Currenty supported - 1 */
125	uint8_t header_version;
126	/* Currenty supported - 1 */
127	uint8_t entry_version;
128	/* Length of directory header in bytes */
129	uint8_t header_length;
130	/*
131	 * 2s complement of 8-bit sum from first byte of header to last byte of
132	 * last directory entry.
133	 */
134	uint8_t checksum;
135	/* ASCII short name of sub-partition */
136	uint8_t name[4];
137} __packed;
138#define SUBPART_DIR_HEADER_SIZE			\
139					(sizeof(struct subpart_dir_header))
140#define SUBPART_DIR_MARKER				0x44504324
141#define SUBPART_DIR_HEADER_VERSION_SUPPORTED	1
142#define SUBPART_DIR_ENTRY_VERSION_SUPPORTED	1
143
144/* Structure for each directory entry for sub-partition */
145struct subpart_dir_entry {
146	/* Name of directory entry - Not guaranteed to be NULL-terminated */
147	uint8_t name[12];
148	/* Offset of entry from beginning of sub-partition */
149	uint32_t offset;
150	/* Length in bytes of sub-directory entry */
151	uint32_t length;
152	/* Must be zero */
153	uint32_t rsvd;
154} __packed;
155#define SUBPART_DIR_ENTRY_SIZE			\
156					(sizeof(struct subpart_dir_entry))
157
158struct subpart_dir {
159	struct subpart_dir_header h;
160	/* In practice, this could be an array of 0 to n entries */
161	struct subpart_dir_entry e[0];
162} __packed;
163
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 * Attributes for various IFWI sub-partitions.
221 * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
222 * BPDT.
223 * NON_CRITICAL_SUBPART = Sub-Partition entry should be present in S-BPDT.
224 * CONTAINS_DIR = Sub-Partition contains directory.
225 * AUTO_GENERATED = Sub-Partition is generated by the tool.
226 * MANDATORY_BPDT_ENTRY = Even if sub-partition is deleted, BPDT should contain
227 * an entry for it with size 0 and offset 0.
228 */
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/* Type value for various IFWI sub-partitions */
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 * There are two order requirements for an IFWI image:
263 * 1. Order in which the sub-partitions lie within the BPDT entries.
264 * 2. Order in which the sub-partitions lie within the image.
265 *
266 * header_order defines #1 i.e. the order in which the sub-partitions should
267 * appear in the BPDT entries. pack_order defines #2 i.e. the order in which
268 * sub-partitions appear in the IFWI image. pack_order controls the offset and
269 * thus sub-partitions would have increasing offsets as we loop over pack_order.
270 */
271const enum bpdt_entry_type bpdt_header_order[MAX_SUBPARTS] = {
272	/* Order of the following entries is mandatory */
273	CSE_IDLM_TYPE,
274	IFP_OVERRIDE_TYPE,
275	S_BPDT_TYPE,
276	CSE_RBE_TYPE,
277	UFS_PHY_TYPE,
278	UFS_GPP_TYPE,
279	/* Order of the following entries is recommended */
280	UEP_TYPE,
281	NVM_CONFIG_TYPE,
282	UFS_RATE_B_TYPE,
283	IBB_TYPE,
284	SMIP_TYPE,
285	PMC_TYPE,
286	CSE_BUP_TYPE,
287	UCODE_TYPE,
288	DEBUG_TOKENS_TYPE,
289	IUNIT_TYPE,
290	CSE_MAIN_TYPE,
291	ISH_TYPE,
292	OBB_TYPE,
293};
294
295const enum bpdt_entry_type bpdt_pack_order[MAX_SUBPARTS] = {
296	/* Order of the following entries is mandatory */
297	UFS_GPP_TYPE,
298	UFS_PHY_TYPE,
299	IFP_OVERRIDE_TYPE,
300	UEP_TYPE,
301	NVM_CONFIG_TYPE,
302	UFS_RATE_B_TYPE,
303	/* Order of the following entries is recommended */
304	IBB_TYPE,
305	SMIP_TYPE,
306	CSE_RBE_TYPE,
307	PMC_TYPE,
308	CSE_BUP_TYPE,
309	UCODE_TYPE,
310	CSE_IDLM_TYPE,
311	DEBUG_TOKENS_TYPE,
312	S_BPDT_TYPE,
313	IUNIT_TYPE,
314	CSE_MAIN_TYPE,
315	ISH_TYPE,
316	OBB_TYPE,
317};
318
319/* Utility functions */
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	/* OEM SMIP */
339	[SMIP_TYPE] = {"SMIP", "SMIP", CONTAINS_DIR, {NULL} },
340	/* CSE RBE */
341	[CSE_RBE_TYPE] = {"RBEP", "CSE_RBE", CONTAINS_DIR |
342			  MANDATORY_BPDT_ENTRY, {NULL} },
343	/* CSE BUP */
344	[CSE_BUP_TYPE] = {"FTPR", "CSE_BUP", CONTAINS_DIR |
345			  MANDATORY_BPDT_ENTRY, {NULL} },
346	/* uCode */
347	[UCODE_TYPE] = {"UCOD", "Microcode", CONTAINS_DIR, {NULL} },
348	/* IBB */
349	[IBB_TYPE] = {"IBBP", "Bootblock", CONTAINS_DIR, {ibbp_dir_add} },
350	/* S-BPDT */
351	[S_BPDT_TYPE] = {"S_BPDT", "S-BPDT", AUTO_GENERATED |
352			 MANDATORY_BPDT_ENTRY, {NULL} },
353	/* OBB */
354	[OBB_TYPE] = {"OBBP", "OEM boot block", CONTAINS_DIR |
355		      NON_CRITICAL_SUBPART, {NULL} },
356	/* CSE Main */
357	[CSE_MAIN_TYPE] = {"NFTP", "CSE_MAIN", CONTAINS_DIR |
358			   NON_CRITICAL_SUBPART, {NULL} },
359	/* ISH */
360	[ISH_TYPE] = {"ISHP", "ISH", NON_CRITICAL_SUBPART, {NULL} },
361	/* CSE IDLM */
362	[CSE_IDLM_TYPE] = {"DLMP", "CSE_IDLM", CONTAINS_DIR |
363			   MANDATORY_BPDT_ENTRY, {NULL} },
364	/* IFP Override */
365	[IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
366			       LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
367			       {NULL} },
368	/* Debug Tokens */
369	[DEBUG_TOKENS_TYPE] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL} },
370	/* UFS Phy Configuration */
371	[UFS_PHY_TYPE] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K |
372			  MANDATORY_BPDT_ENTRY, {NULL} },
373	/* UFS GPP LUN ID */
374	[UFS_GPP_TYPE] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K |
375			  MANDATORY_BPDT_ENTRY, {NULL} },
376	/* PMC */
377	[PMC_TYPE] = {"PMCP", "PMC firmware", CONTAINS_DIR, {NULL} },
378	/* IUNIT */
379	[IUNIT_TYPE] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART, {NULL} },
380	/* NVM Config */
381	[NVM_CONFIG_TYPE] = {"NVM_CONFIG", "NVM Config", 0, {NULL} },
382	/* UEP */
383	[UEP_TYPE] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
384		      {NULL} },
385	/* UFS Rate B Config */
386	[UFS_RATE_B_TYPE] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL} },
387};
388
389struct ifwi_image {
390	/* Data read from input file */
391	struct buffer input_buff;
392
393	/* BPDT header and entries */
394	struct buffer bpdt;
395	size_t input_ifwi_start_offset;
396	size_t input_ifwi_end_offset;
397
398	/* Subpartition content */
399	struct buffer subpart_buf[MAX_SUBPARTS];
400} ifwi_image;
401
402/* Buffer and file I/O */
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 * Shrink a buffer toward the beginning of its previous space.
430 * Afterward, buffer_delete() remains the means of cleaning it up
431 */
432static inline void buffer_set_size(struct buffer *b, size_t size)
433{
434	b->size = size;
435}
436
437/* Splice a buffer into another buffer. Note that it's up to the caller to
438 * bounds check the offset and size. The resulting buffer is backed by the same
439 * storage as the original, so although it is valid to buffer_delete() either
440 * one of them, doing so releases both simultaneously
441 */
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 * Shrink a buffer toward the end of its previous space.
453 * Afterward, buffer_delete() remains the means of cleaning it up
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/* Returns the start of the underlying buffer, with the offset undone */
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/* Little-Endian functions */
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 * Read header/entry members in little-endian format.
692 * Returns the offset upto which the read was performed.
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 * Convert to little endian format.
720 * Returns the offset upto which the fixup was performed.
721 */
722static size_t fix_member(void *data, size_t offset, size_t size_bytes)
723{
724	void *src = (uint8_t *)data + offset;
725
726	switch (size_bytes) {
727	case 1:
728		write_at_le8(data, *(uint8_t *)src, offset);
729		break;
730	case 2:
731		write_at_le16(data, *(uint16_t *)src, offset);
732		break;
733	case 4:
734		write_at_le32(data, *(uint32_t *)src, offset);
735		break;
736	case 8:
737		write_at_le64(data, *(uint64_t *)src, offset);
738		break;
739	default:
740		ERROR("Write size not supported %zd\n", size_bytes);
741		exit(-1);
742	}
743	return (offset + size_bytes);
744}
745
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 * Given type of sub-partition, identify BPDT entry for it.
876 * Sub-Partition could lie either within BPDT or S-BPDT.
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 * Find sub-partition type given its name. If the name does not exist, returns
917 * -1.
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 * Read the content of a sub-partition from input file and store it in
939 * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
940 *
941 * Returns the maximum offset occupied by the sub-partitions.
942 */
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		 * Sub-partitions in IFWI image are not in the same order as
974		 * in BPDT entries. BPDT entires are in header_order whereas
975		 * sub-partition offsets in the image are in pack_order.
976		 */
977		if ((e[i].offset + e[i].size) > max_offset)
978			max_offset = e[i].offset + e[i].size;
979
980		/*
981		 * S-BPDT sub-partition contains information about all the
982		 * non-critical sub-partitions. Thus, size of S-BPDT
983		 * sub-partition equals size of S-BPDT plus size of all the
984		 * non-critical sub-partitions. Thus, reading whole of S-BPDT
985		 * here would be redundant as the non-critical partitions are
986		 * read and allocated buffers separately. Also, S-BPDT requires
987		 * special handling for reading header and entries.
988		 */
989		if (type == S_BPDT_TYPE)
990			continue;
991
992		buf = &ifwi_image.subpart_buf[type];
993
994		alloc_buffer(buf, e[i].size, subparts[type].name);
995		memcpy(buffer_get(buf), (uint8_t *)data + e[i].offset,
996		       e[i].size);
997	}
998
999	assert(max_offset);
1000	return max_offset;
1001}
1002
1003/*
1004 * Allocate buffer for bpdt header, entries and all sub-partition content.
1005 * Returns offset in data where BPDT ends.
1006 */
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	/* Buffer to read BPDT header and entries */
1016	alloc_buffer(b, get_bpdt_size(&bpdt_header), name);
1017
1018	struct bpdt *bpdt = buffer_get(b);
1019
1020	memcpy(&bpdt->h, &bpdt_header, BPDT_HEADER_SIZE);
1021
1022	/*
1023	 * If no entries are present, maximum offset occupied is (offset +
1024	 * BPDT_HEADER_SIZE).
1025	 */
1026	if (bpdt->h.descriptor_count == 0)
1027		return (offset + BPDT_HEADER_SIZE);
1028
1029	/* Read all entries */
1030	assert((offset + get_bpdt_size(&bpdt->h)) < size);
1031	bpdt_read_entries((uint8_t *)data + offset + BPDT_HEADER_SIZE, bpdt,
1032			  name);
1033
1034	/* Read all sub-partition content in subpart_buf */
1035	return read_subpart_buf(data, size, &bpdt->e[0],
1036				bpdt->h.descriptor_count);
1037}
1038
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	/* 2s complement */
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	/* Read Subpart_Dir header */
1115	assert(size >= SUBPART_DIR_HEADER_SIZE);
1116	offset = read_member(data, offset, sizeof(hdr.marker), &hdr.marker);
1117	offset = read_member(data, offset, sizeof(hdr.num_entries),
1118			     &hdr.num_entries);
1119	offset = read_member(data, offset, sizeof(hdr.header_version),
1120			     &hdr.header_version);
1121	offset = read_member(data, offset, sizeof(hdr.entry_version),
1122			     &hdr.entry_version);
1123	offset = read_member(data, offset, sizeof(hdr.header_length),
1124			     &hdr.header_length);
1125	offset = read_member(data, offset, sizeof(hdr.checksum), &hdr.checksum);
1126	memcpy(hdr.name, data + offset, sizeof(hdr.name));
1127	offset += sizeof(hdr.name);
1128
1129	validate_subpart_dir_without_checksum((struct subpart_dir *)&hdr, name);
1130
1131	assert(size > subpart_dir_size(&hdr));
1132	alloc_buffer(subpart_dir_buf, subpart_dir_size(&hdr), "Subpart Dir");
1133	memcpy(buffer_get(subpart_dir_buf), &hdr, SUBPART_DIR_HEADER_SIZE);
1134
1135	/* Read Subpart Dir entries */
1136	struct subpart_dir *subpart_dir = buffer_get(subpart_dir_buf);
1137	struct subpart_dir_entry *e = &subpart_dir->e[0];
1138	uint32_t i;
1139
1140	for (i = 0; i < hdr.num_entries; i++) {
1141		memcpy(e[i].name, data + offset, sizeof(e[i].name));
1142		offset += sizeof(e[i].name);
1143		offset = read_member(data, offset, sizeof(e[i].offset),
1144				     &e[i].offset);
1145		offset = read_member(data, offset, sizeof(e[i].length),
1146				     &e[i].length);
1147		offset = read_member(data, offset, sizeof(e[i].rsvd),
1148				     &e[i].rsvd);
1149	}
1150
1151	validate_subpart_dir_with_checksum(subpart_dir, name);
1152
1153	print_subpart_dir(subpart_dir);
1154}
1155
1156/* Parse input image file to identify different sub-partitions */
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	/* Read input file */
1165	if (buffer_from_file(buff, image_name)) {
1166		ERROR("Failed to read input file %s.\n", image_name);
1167		return -1;
1168	}
1169
1170	INFO("Buffer %p size 0x%zx\n", buff->data, buff->size);
1171
1172	/* Look for BPDT signature at 4K intervals */
1173	size_t offset = 0;
1174	void *data = buffer_get(buff);
1175
1176	while (offset < buffer_size(buff)) {
1177		if (read_at_le32(data, offset) == BPDT_SIGNATURE)
1178			break;
1179		offset += 4 * KiB;
1180	}
1181
1182	if (offset >= buffer_size(buff)) {
1183		ERROR("Image does not contain BPDT!!\n");
1184		return -1;
1185	}
1186
1187	ifwi_image.input_ifwi_start_offset = offset;
1188	INFO("BPDT starts at offset 0x%zx.\n", offset);
1189
1190	data = (uint8_t *)data + offset;
1191	size_t ifwi_size = buffer_size(buff) - offset;
1192
1193	/* Read BPDT and sub-partitions */
1194	uintptr_t end_offset;
1195
1196	end_offset = ifwi_image.input_ifwi_start_offset +
1197		alloc_bpdt_buffer(data, ifwi_size, 0, &ifwi_image.bpdt, "BPDT");
1198
1199	/* Parse S-BPDT, if any */
1200	parse_sbpdt(data, ifwi_size);
1201
1202	/*
1203	 * Store end offset of IFWI. Required for copying any trailing non-IFWI
1204	 * part of the image.
1205	 * ASSUMPTION: IFWI image always ends on a 4K boundary.
1206	 */
1207	ifwi_image.input_ifwi_end_offset = ALIGN(end_offset, 4 * KiB);
1208	DEBUG("Parsing done.\n");
1209
1210	return 0;
1211}
1212
1213/*
1214 * This function is used by repack to count the number of BPDT and S-BPDT
1215 * entries that are present. It frees the current buffers used by the entries
1216 * and allocates fresh buffers that can be used for repacking. Returns BPDT
1217 * entries which are empty and need to be filled in.
1218 */
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	 * If buffer does not have the required size, allocate a fresh buffer.
1227	 */
1228	if (buffer_size(b) != size) {
1229		struct buffer temp;
1230
1231		alloc_buffer(&temp, size, b->name);
1232		memcpy(buffer_get(&temp), buffer_get(b), buffer_size(b));
1233		buffer_delete(b);
1234		*b = temp;
1235	}
1236
1237	struct bpdt *bpdt = buffer_get(b);
1238	uint8_t *ptr = (uint8_t *)&bpdt->e[0];
1239	size_t entries_size = BPDT_ENTRY_SIZE * count;
1240
1241	/* Zero out BPDT entries */
1242	memset(ptr, 0, entries_size);
1243	/* Fill any pad-space with FF */
1244	memset(ptr + entries_size, 0xFF, size - bpdt_size);
1245
1246	bpdt->h.descriptor_count = count;
1247}
1248
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	/* Count number of BPDT and S-BPDT entries */
1255	for (i = 0; i < MAX_SUBPARTS; i++) {
1256		if (buffer_size(&ifwi_image.subpart_buf[i]) == 0) {
1257			if (subparts[i].attr & MANDATORY_BPDT_ENTRY) {
1258				bpdt_count++;
1259				dummy_bpdt_count++;
1260			}
1261			continue;
1262		}
1263
1264		if (subparts[i].attr & NON_CRITICAL_SUBPART)
1265			sbpdt_count++;
1266		else
1267			bpdt_count++;
1268	}
1269
1270	DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count,
1271	      dummy_bpdt_count, sbpdt_count);
1272
1273	/* Update BPDT if required */
1274	size_t bpdt_size = max(BPDT_MIN_SIZE,
1275			       BPDT_HEADER_SIZE + bpdt_count * BPDT_ENTRY_SIZE);
1276	__bpdt_reset(&ifwi_image.bpdt, bpdt_count, bpdt_size);
1277
1278	/* Update S-BPDT if required */
1279	bpdt_size = ALIGN(BPDT_HEADER_SIZE + sbpdt_count * BPDT_ENTRY_SIZE,
1280			  4 * KiB);
1281	__bpdt_reset(&ifwi_image.subpart_buf[S_BPDT_TYPE], sbpdt_count,
1282		     bpdt_size);
1283}
1284
1285/* Initialize BPDT entries in header order */
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/* Initialize offsets of entries using pack order */
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	 * There are two types of sub-partitions that need to be handled here:
1353	 *   1. Sub-partitions that lie within the same 4K as BPDT
1354	 *   2. Sub-partitions that lie outside the 4K of BPDT
1355	 *
1356	 * For sub-partitions of type # 1, there is no requirement on the start
1357	 * or end of the sub-partition. They need to be packed in without any
1358	 * holes left in between. If there is any empty space left after the end
1359	 * of the last sub-partition in 4K of BPDT, then that space needs to be
1360	 * padded with FF bytes, but the size of the last sub-partition remains
1361	 * unchanged.
1362	 *
1363	 * For sub-partitions of type # 2, both the start and end should be a
1364	 * multiple of 4K. If not, then it needs to be padded with FF bytes and
1365	 * size adjusted such that the sub-partition ends on 4K boundary.
1366	 */
1367
1368	/* #1 Sub-partitions that lie within same 4K as BPDT */
1369	struct buffer *last_bpdt_buff = &ifwi_image.bpdt;
1370
1371	for (i = 0; i < MAX_SUBPARTS; i++) {
1372		type = bpdt_pack_order[i];
1373		curr = find_entry_by_type(type);
1374
1375		if (!curr || curr->size == 0)
1376			continue;
1377
1378		if (!(subparts[type].attr & LIES_WITHIN_BPDT_4K))
1379			continue;
1380
1381		curr->offset = curr_offset;
1382		curr_offset = curr->offset + curr->size;
1383		last_bpdt_buff = &ifwi_image.subpart_buf[type];
1384		DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
1385		      type, curr_offset, curr->offset, curr->size,
1386		      buffer_size(&ifwi_image.subpart_buf[type]));
1387	}
1388
1389	/* Pad ff bytes if there is any empty space left in BPDT 4K */
1390	curr_end = ALIGN(curr_offset, 4 * KiB);
1391	pad_buffer(last_bpdt_buff,
1392		   buffer_size(last_bpdt_buff) + (curr_end - curr_offset));
1393	curr_offset = curr_end;
1394
1395	/* #2 Sub-partitions that lie outside of BPDT 4K */
1396	for (i = 0; i < MAX_SUBPARTS; i++) {
1397		type = bpdt_pack_order[i];
1398		curr = find_entry_by_type(type);
1399
1400		if (!curr || curr->size == 0)
1401			continue;
1402
1403		if (subparts[type].attr & LIES_WITHIN_BPDT_4K)
1404			continue;
1405
1406		assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1407		curr->offset = curr_offset;
1408		curr_end = ALIGN(curr->offset + curr->size, 4 * KiB);
1409		curr->size = curr_end - curr->offset;
1410
1411		pad_buffer(&ifwi_image.subpart_buf[type], curr->size);
1412
1413		curr_offset = curr_end;
1414		DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
1415		      type, curr_offset, curr->offset, curr->size,
1416		      buffer_size(&ifwi_image.subpart_buf[type]));
1417	}
1418
1419	/*
1420	 * Update size of S-BPDT to include size of all non-critical
1421	 * sub-partitions.
1422	 *
1423	 * Assumption: S-BPDT always lies at the end of IFWI image.
1424	 */
1425	curr = find_entry_by_type(S_BPDT_TYPE);
1426	assert(curr);
1427
1428	assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1429	curr->size = curr_offset - curr->offset;
1430}
1431
1432/* Convert all members of BPDT to little-endian format */
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(s, offset, sizeof(h->signature));
1445	offset = fix_member(s, offset, sizeof(h->descriptor_count));
1446	offset = fix_member(s, offset, sizeof(h->bpdt_version));
1447	offset = fix_member(s, offset, sizeof(h->xor_redundant_block));
1448	offset = fix_member(s, offset, sizeof(h->ifwi_version));
1449	offset = fix_member(s, offset, sizeof(h->fit_tool_version));
1450
1451	uint32_t i;
1452
1453	for (i = 0; i < count; i++) {
1454		offset = fix_member(s, offset, sizeof(e[i].type));
1455		offset = fix_member(s, offset, sizeof(e[i].flags));
1456		offset = fix_member(s, offset, sizeof(e[i].offset));
1457		offset = fix_member(s, offset, sizeof(e[i].size));
1458	}
1459}
1460
1461/* Write BPDT to output buffer after fixup */
1462static void bpdt_write(struct buffer *dst, size_t offset, struct buffer *src)
1463{
1464	bpdt_fixup_write_buffer(src);
1465	memcpy(buffer_get(dst) + offset, buffer_get(src), buffer_size(src));
1466}
1467
1468/*
1469 * Follows these steps to re-create image:
1470 * 1. Write any non-IFWI prefix.
1471 * 2. Write out BPDT header and entries.
1472 * 3. Write sub-partition buffers to respective offsets.
1473 * 4. Write any non-IFWI suffix.
1474 *
1475 * While performing the above steps, make sure that any empty holes are filled
1476 * with FF.
1477 */
1478static void ifwi_write(const char *image_name)
1479{
1480	struct bpdt_entry *s = find_entry_by_type(S_BPDT_TYPE);
1481
1482	assert(s);
1483
1484	size_t ifwi_start, ifwi_end, file_end;
1485
1486	ifwi_start = ifwi_image.input_ifwi_start_offset;
1487	ifwi_end = ifwi_start + ALIGN(s->offset + s->size, 4 * KiB);
1488	file_end = ifwi_end + (buffer_size(&ifwi_image.input_buff) -
1489			       ifwi_image.input_ifwi_end_offset);
1490
1491	struct buffer b;
1492
1493	alloc_buffer(&b, file_end, "Final-IFWI");
1494
1495	uint8_t *input_data = buffer_get(&ifwi_image.input_buff);
1496	uint8_t *output_data = buffer_get(&b);
1497
1498	DEBUG("ifwi_start:0x%zx, ifwi_end:0x%zx, file_end:0x%zx\n", ifwi_start,
1499	      ifwi_end, file_end);
1500
1501	/* Copy non-IFWI prefix, if any */
1502	memcpy(output_data, input_data, ifwi_start);
1503
1504	DEBUG("Copied non-IFWI prefix (offset=0x0, size=0x%zx).\n", ifwi_start);
1505
1506	struct buffer ifwi;
1507
1508	buffer_splice(&ifwi, &b, ifwi_start, ifwi_end - ifwi_start);
1509	uint8_t *ifwi_data = buffer_get(&ifwi);
1510
1511	/* Copy sub-partitions using pack_order */
1512	struct bpdt_entry *curr;
1513	struct buffer *subpart_buf;
1514	int i, type;
1515
1516	for (i = 0; i < MAX_SUBPARTS; i++) {
1517		type = bpdt_pack_order[i];
1518
1519		if (type == S_BPDT_TYPE)
1520			continue;
1521
1522		curr = find_entry_by_type(type);
1523
1524		if (!curr || !curr->size)
1525			continue;
1526
1527		subpart_buf = &ifwi_image.subpart_buf[type];
1528
1529		DEBUG("curr->offset=0x%x, curr->size=0x%x, type=%d, write_size=0x%zx\n",
1530		      curr->offset, curr->size, type, buffer_size(subpart_buf));
1531
1532		assert((curr->offset + buffer_size(subpart_buf)) <=
1533		       buffer_size(&ifwi));
1534
1535		memcpy(ifwi_data + curr->offset, buffer_get(subpart_buf),
1536		       buffer_size(subpart_buf));
1537	}
1538
1539	/* Copy non-IFWI suffix, if any */
1540	if (ifwi_end != file_end) {
1541		memcpy(output_data + ifwi_end,
1542		       input_data + ifwi_image.input_ifwi_end_offset,
1543		       file_end - ifwi_end);
1544		DEBUG("Copied non-IFWI suffix (offset=0x%zx,size=0x%zx).\n",
1545		      ifwi_end, file_end - ifwi_end);
1546	}
1547
1548	/*
1549	 * Convert BPDT to little-endian format and write it to output buffer.
1550	 * S-BPDT is written first and then BPDT.
1551	 */
1552	bpdt_write(&ifwi, s->offset, &ifwi_image.subpart_buf[S_BPDT_TYPE]);
1553	bpdt_write(&ifwi, 0, &ifwi_image.bpdt);
1554
1555	if (buffer_write_file(&b, image_name)) {
1556		ERROR("File write error\n");
1557		exit(-1);
1558	}
1559
1560	buffer_delete(&b);
1561	printf("Image written successfully to %s.\n", image_name);
1562}
1563
1564/*
1565 * Calculate size and offset of each sub-partition again since it might have
1566 * changed because of add/delete operation. Also, re-create BPDT and S-BPDT
1567 * entries and write back the new IFWI image to file.
1568 */
1569static void ifwi_repack(void)
1570{
1571	bpdt_reset();
1572	bpdt_entries_init_header_order();
1573	bpdt_entries_init_pack_order();
1574
1575	struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1576
1577	bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1578
1579	b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1580	bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1581
1582	DEBUG("Repack done.. writing image.\n");
1583	ifwi_write(param.image_name);
1584}
1585
1586static void init_subpart_dir_header(struct subpart_dir_header *hdr,
1587				    size_t count, const char *name)
1588{
1589	memset(hdr, 0, sizeof(*hdr));
1590
1591	hdr->marker = SUBPART_DIR_MARKER;
1592	hdr->num_entries = count;
1593	hdr->header_version = SUBPART_DIR_HEADER_VERSION_SUPPORTED;
1594	hdr->entry_version = SUBPART_DIR_ENTRY_VERSION_SUPPORTED;
1595	hdr->header_length = SUBPART_DIR_HEADER_SIZE;
1596	memcpy(hdr->name, name, sizeof(hdr->name));
1597}
1598
1599static size_t init_subpart_dir_entry(struct subpart_dir_entry *e,
1600				     struct buffer *b, size_t offset)
1601{
1602	memset(e, 0, sizeof(*e));
1603
1604	assert(strlen(b->name) <= sizeof(e->name));
1605	strncpy((char *)e->name, (char *)b->name, sizeof(e->name));
1606	e->offset = offset;
1607	e->length = buffer_size(b);
1608
1609	return (offset + buffer_size(b));
1610}
1611
1612static void init_manifest_header(struct manifest_header *hdr, size_t size)
1613{
1614	memset(hdr, 0, sizeof(*hdr));
1615
1616	hdr->header_type = 0x4;
1617	assert((MANIFEST_HDR_SIZE % DWORD_SIZE) == 0);
1618	hdr->header_length = MANIFEST_HDR_SIZE / DWORD_SIZE;
1619	hdr->header_version = 0x10000;
1620	hdr->vendor = 0x8086;
1621
1622	struct tm *local_time;
1623	time_t curr_time;
1624	char buffer[11];
1625
1626	curr_time = time(NULL);
1627	local_time = localtime(&curr_time);
1628	assert(local_time != NULL);
1629
1630	strftime(buffer, sizeof(buffer), "0x%Y%m%d", local_time);
1631	hdr->date = strtoul(buffer, NULL, 16);
1632
1633	assert((size % DWORD_SIZE) == 0);
1634	hdr->size = size / DWORD_SIZE;
1635	hdr->id = MANIFEST_ID_MAGIC;
1636}
1637
1638static void init_signed_pkg_info_ext(struct signed_pkg_info_ext *ext,
1639				     size_t count, const char *name)
1640{
1641	memset(ext, 0, sizeof(*ext));
1642
1643	ext->ext_type = SIGNED_PKG_INFO_EXT_TYPE;
1644	ext->ext_length = SIGNED_PKG_INFO_EXT_SIZE + count * MODULE_SIZE;
1645	memcpy(ext->name, name, sizeof(ext->name));
1646}
1647
1648static void subpart_dir_fixup_write_buffer(struct buffer *buf)
1649{
1650	struct subpart_dir *s = buffer_get(buf);
1651	struct subpart_dir_header *h = &s->h;
1652	struct subpart_dir_entry *e = &s->e[0];
1653
1654	size_t count = h->num_entries;
1655	size_t offset = 0;
1656
1657	offset = fix_member(s, offset, sizeof(h->marker));
1658	offset = fix_member(s, offset, sizeof(h->num_entries));
1659	offset = fix_member(s, offset, sizeof(h->header_version));
1660	offset = fix_member(s, offset, sizeof(h->entry_version));
1661	offset = fix_member(s, offset, sizeof(h->header_length));
1662	offset = fix_member(s, offset, sizeof(h->checksum));
1663	offset += sizeof(h->name);
1664
1665	uint32_t i;
1666
1667	for (i = 0; i < count; i++) {
1668		offset += sizeof(e[i].name);
1669		offset = fix_member(s, offset, sizeof(e[i].offset));
1670		offset = fix_member(s, offset, sizeof(e[i].length));
1671		offset = fix_member(s, offset, sizeof(e[i].rsvd));
1672	}
1673}
1674
1675static void create_subpart(struct buffer *dst, struct buffer *info[],
1676			   size_t count, const char *name)
1677{
1678	struct buffer subpart_dir_buff;
1679	size_t size = SUBPART_DIR_HEADER_SIZE + count * SUBPART_DIR_ENTRY_SIZE;
1680
1681	alloc_buffer(&subpart_dir_buff, size, "subpart-dir");
1682
1683	struct subpart_dir_header *h = buffer_get(&subpart_dir_buff);
1684	struct subpart_dir_entry *e = (struct subpart_dir_entry *)(h + 1);
1685
1686	init_subpart_dir_header(h, count, name);
1687
1688	size_t curr_offset = size;
1689	size_t i;
1690
1691	for (i = 0; i < count; i++) {
1692		curr_offset = init_subpart_dir_entry(&e[i], info[i],
1693						     curr_offset);
1694	}
1695
1696	alloc_buffer(dst, curr_offset, name);
1697	uint8_t *data = buffer_get(dst);
1698
1699	for (i = 0; i < count; i++) {
1700		memcpy(data + e[i].offset, buffer_get(info[i]),
1701		       buffer_size(info[i]));
1702	}
1703
1704	h->checksum = calc_checksum(buffer_get(&subpart_dir_buff));
1705
1706	struct subpart_dir *dir = buffer_get(&subpart_dir_buff);
1707
1708	print_subpart_dir(dir);
1709
1710	subpart_dir_fixup_write_buffer(&subpart_dir_buff);
1711	memcpy(data, dir, buffer_size(&subpart_dir_buff));
1712
1713	buffer_delete(&subpart_dir_buff);
1714}
1715
1716static enum ifwi_ret ibbp_dir_add(int type)
1717{
1718	struct buffer manifest;
1719	struct signed_pkg_info_ext *ext;
1720	struct buffer ibbl;
1721	struct buffer ibb;
1722
1723#define DUMMY_IBB_SIZE			(4 * KiB)
1724
1725	assert(type == IBB_TYPE);
1726
1727	/*
1728	 * Entry # 1 - IBBP.man
1729	 * Contains manifest header and signed pkg info extension.
1730	 */
1731	size_t size = MANIFEST_HDR_SIZE + SIGNED_PKG_INFO_EXT_SIZE;
1732
1733	alloc_buffer(&manifest, size, "IBBP.man");
1734
1735	struct manifest_header *man_hdr = buffer_get(&manifest);
1736
1737	init_manifest_header(man_hdr, size);
1738
1739	ext = (struct signed_pkg_info_ext *)(man_hdr + 1);
1740
1741	init_signed_pkg_info_ext(ext, 0, subparts[type].name);
1742
1743	/* Entry # 2 - IBBL */
1744	if (buffer_from_file(&ibbl, param.file_name))
1745		return COMMAND_ERR;
1746
1747	/* Entry # 3 - IBB */
1748	alloc_buffer(&ibb, DUMMY_IBB_SIZE, "IBB");
1749	memset(buffer_get(&ibb), 0xFF, DUMMY_IBB_SIZE);
1750
1751	/* Create subpartition */
1752	struct buffer *info[] = {
1753		&manifest, &ibbl, &ibb,
1754	};
1755	create_subpart(&ifwi_image.subpart_buf[type], &info[0],
1756		       ARRAY_SIZE(info), subparts[type].name);
1757
1758	return REPACK_REQUIRED;
1759}
1760
1761static enum ifwi_ret ifwi_raw_add(int type)
1762{
1763	if (buffer_from_file(&ifwi_image.subpart_buf[type], param.file_name))
1764		return COMMAND_ERR;
1765
1766	printf("Sub-partition %s(%d) added from file %s.\n", param.subpart_name,
1767	       type, param.file_name);
1768	return REPACK_REQUIRED;
1769}
1770
1771static enum ifwi_ret ifwi_dir_add(int type)
1772{
1773	if (!(subparts[type].attr & CONTAINS_DIR) ||
1774	    !subparts[type].dir_ops.dir_add) {
1775		ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1776		      subparts[type].name, type);
1777		return COMMAND_ERR;
1778	}
1779
1780	if (!param.dentry_name) {
1781		ERROR("%s: -e option required\n", __func__);
1782		return COMMAND_ERR;
1783	}
1784
1785	enum ifwi_ret ret = subparts[type].dir_ops.dir_add(type);
1786
1787	if (ret != COMMAND_ERR)
1788		printf("Sub-partition %s(%d) entry %s added from file %s.\n",
1789		       param.subpart_name, type, param.dentry_name,
1790		       param.file_name);
1791	else
1792		ERROR("Sub-partition dir operation failed.\n");
1793
1794	return ret;
1795}
1796
1797static enum ifwi_ret ifwi_add(void)
1798{
1799	if (!param.file_name) {
1800		ERROR("%s: -f option required\n", __func__);
1801		return COMMAND_ERR;
1802	}
1803
1804	if (!param.subpart_name) {
1805		ERROR("%s: -n option required\n", __func__);
1806		return COMMAND_ERR;
1807	}
1808
1809	int type = find_type_by_name(param.subpart_name);
1810
1811	if (type == -1)
1812		return COMMAND_ERR;
1813
1814	const struct subpart_info *curr_subpart = &subparts[type];
1815
1816	if (curr_subpart->attr & AUTO_GENERATED) {
1817		ERROR("Cannot add auto-generated sub-partitions.\n");
1818		return COMMAND_ERR;
1819	}
1820
1821	if (buffer_size(&ifwi_image.subpart_buf[type])) {
1822		ERROR("Image already contains sub-partition %s(%d).\n",
1823		      param.subpart_name, type);
1824		return COMMAND_ERR;
1825	}
1826
1827	if (param.dir_ops)
1828		return ifwi_dir_add(type);
1829
1830	return ifwi_raw_add(type);
1831}
1832
1833static enum ifwi_ret ifwi_delete(void)
1834{
1835	if (!param.subpart_name) {
1836		ERROR("%s: -n option required\n", __func__);
1837		return COMMAND_ERR;
1838	}
1839
1840	int type = find_type_by_name(param.subpart_name);
1841
1842	if (type == -1)
1843		return COMMAND_ERR;
1844
1845	const struct subpart_info *curr_subpart = &subparts[type];
1846
1847	if (curr_subpart->attr & AUTO_GENERATED) {
1848		ERROR("Cannot delete auto-generated sub-partitions.\n");
1849		return COMMAND_ERR;
1850	}
1851
1852	if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1853		printf("Image does not contain sub-partition %s(%d).\n",
1854		       param.subpart_name, type);
1855		return NO_ACTION_REQUIRED;
1856	}
1857
1858	buffer_delete(&ifwi_image.subpart_buf[type]);
1859	printf("Sub-Partition %s(%d) deleted.\n", subparts[type].name, type);
1860	return REPACK_REQUIRED;
1861}
1862
1863static enum ifwi_ret ifwi_dir_extract(int type)
1864{
1865	if (!(subparts[type].attr & CONTAINS_DIR)) {
1866		ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
1867		      subparts[type].name, type);
1868		return COMMAND_ERR;
1869	}
1870
1871	if (!param.dentry_name) {
1872		ERROR("%s: -e option required.\n", __func__);
1873		return COMMAND_ERR;
1874	}
1875
1876	struct buffer subpart_dir_buff;
1877
1878	parse_subpart_dir(&subpart_dir_buff, &ifwi_image.subpart_buf[type],
1879			  subparts[type].name);
1880
1881	uint32_t i;
1882	struct subpart_dir *s = buffer_get(&subpart_dir_buff);
1883
1884	for (i = 0; i < s->h.num_entries; i++) {
1885		if (!strncmp((char *)s->e[i].name, param.dentry_name,
1886			     sizeof(s->e[i].name)))
1887			break;
1888	}
1889
1890	if (i == s->h.num_entries) {
1891		ERROR("Entry %s not found in subpartition for %s.\n",
1892		      param.dentry_name, param.subpart_name);
1893		exit(-1);
1894	}
1895
1896	struct buffer dst;
1897
1898	DEBUG("Splicing buffer at 0x%x size 0x%x\n", s->e[i].offset,
1899	      s->e[i].length);
1900	buffer_splice(&dst, &ifwi_image.subpart_buf[type], s->e[i].offset,
1901		      s->e[i].length);
1902
1903	if (buffer_write_file(&dst, param.file_name))
1904		return COMMAND_ERR;
1905
1906	printf("Sub-Partition %s(%d), entry(%s) stored in %s.\n",
1907	       param.subpart_name, type, param.dentry_name, param.file_name);
1908
1909	return NO_ACTION_REQUIRED;
1910}
1911
1912static enum ifwi_ret ifwi_raw_extract(int type)
1913{
1914	if (buffer_write_file(&ifwi_image.subpart_buf[type], param.file_name))
1915		return COMMAND_ERR;
1916
1917	printf("Sub-Partition %s(%d) stored in %s.\n", param.subpart_name, type,
1918	       param.file_name);
1919
1920	return NO_ACTION_REQUIRED;
1921}
1922
1923static enum ifwi_ret ifwi_extract(void)
1924{
1925	if (!param.file_name) {
1926		ERROR("%s: -f option required\n", __func__);
1927		return COMMAND_ERR;
1928	}
1929
1930	if (!param.subpart_name) {
1931		ERROR("%s: -n option required\n", __func__);
1932		return COMMAND_ERR;
1933	}
1934
1935	int type = find_type_by_name(param.subpart_name);
1936
1937	if (type == -1)
1938		return COMMAND_ERR;
1939
1940	if (type == S_BPDT_TYPE) {
1941		INFO("Tool does not support raw extract for %s\n",
1942		     param.subpart_name);
1943		return NO_ACTION_REQUIRED;
1944	}
1945
1946	if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
1947		ERROR("Image does not contain sub-partition %s(%d).\n",
1948		      param.subpart_name, type);
1949		return COMMAND_ERR;
1950	}
1951
1952	INFO("Extracting sub-partition %s(%d).\n", param.subpart_name, type);
1953	if (param.dir_ops)
1954		return ifwi_dir_extract(type);
1955
1956	return ifwi_raw_extract(type);
1957}
1958
1959static enum ifwi_ret ifwi_print(void)
1960{
1961	verbose += 2;
1962
1963	struct bpdt *b = buffer_get(&ifwi_image.bpdt);
1964
1965	bpdt_print_header(&b->h, "BPDT");
1966	bpdt_print_entries(&b->e[0], b->h.descriptor_count, "BPDT");
1967
1968	b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1969	bpdt_print_header(&b->h, "S-BPDT");
1970	bpdt_print_entries(&b->e[0], b->h.descriptor_count, "S-BPDT");
1971
1972	if (param.dir_ops == 0) {
1973		verbose -= 2;
1974		return NO_ACTION_REQUIRED;
1975	}
1976
1977	int i;
1978	struct buffer subpart_dir_buf;
1979
1980	for (i = 0; i < MAX_SUBPARTS ; i++) {
1981		if (!(subparts[i].attr & CONTAINS_DIR) ||
1982		    (buffer_size(&ifwi_image.subpart_buf[i]) == 0))
1983			continue;
1984
1985		parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[i],
1986				  subparts[i].name);
1987		buffer_delete(&subpart_dir_buf);
1988	}
1989
1990	verbose -= 2;
1991
1992	return NO_ACTION_REQUIRED;
1993}
1994
1995static enum ifwi_ret ifwi_raw_replace(int type)
1996{
1997	buffer_delete(&ifwi_image.subpart_buf[type]);
1998	return ifwi_raw_add(type);
1999}
2000
2001static enum ifwi_ret ifwi_dir_replace(int type)
2002{
2003	if (!(subparts[type].attr & CONTAINS_DIR)) {
2004		ERROR("Sub-Partition %s(%d) does not support dir ops.\n",
2005		      subparts[type].name, type);
2006		return COMMAND_ERR;
2007	}
2008
2009	if (!param.dentry_name) {
2010		ERROR("%s: -e option required.\n", __func__);
2011		return COMMAND_ERR;
2012	}
2013
2014	struct buffer subpart_dir_buf;
2015
2016	parse_subpart_dir(&subpart_dir_buf, &ifwi_image.subpart_buf[type],
2017			  subparts[type].name);
2018
2019	uint32_t i;
2020	struct subpart_dir *s = buffer_get(&subpart_dir_buf);
2021
2022	for (i = 0; i < s->h.num_entries; i++) {
2023		if (!strcmp((char *)s->e[i].name, param.dentry_name))
2024			break;
2025	}
2026
2027	if (i == s->h.num_entries) {
2028		ERROR("Entry %s not found in subpartition for %s.\n",
2029		      param.dentry_name, param.subpart_name);
2030		exit(-1);
2031	}
2032
2033	struct buffer b;
2034
2035	if (buffer_from_file(&b, param.file_name)) {
2036		ERROR("Failed to read %s\n", param.file_name);
2037		exit(-1);
2038	}
2039
2040	struct buffer dst;
2041	size_t dst_size = buffer_size(&ifwi_image.subpart_buf[type]) +
2042				      buffer_size(&b) - s->e[i].length;
2043	size_t subpart_start = s->e[i].offset;
2044	size_t subpart_end = s->e[i].offset + s->e[i].length;
2045
2046	alloc_buffer(&dst, dst_size, ifwi_image.subpart_buf[type].name);
2047
2048	uint8_t *src_data = buffer_get(&ifwi_image.subpart_buf[type]);
2049	uint8_t *dst_data = buffer_get(&dst);
2050	size_t curr_offset = 0;
2051
2052	/* Copy data before the sub-partition entry */
2053	memcpy(dst_data + curr_offset, src_data, subpart_start);
2054	curr_offset += subpart_start;
2055
2056	/* Copy sub-partition entry */
2057	memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
2058	curr_offset += buffer_size(&b);
2059
2060	/* Copy remaining data */
2061	memcpy(dst_data + curr_offset, src_data + subpart_end,
2062	       buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end);
2063
2064	/* Update sub-partition buffer */
2065	int offset = s->e[i].offset;
2066
2067	buffer_delete(&ifwi_image.subpart_buf[type]);
2068	ifwi_image.subpart_buf[type] = dst;
2069
2070	/* Update length of entry in the subpartition */
2071	s->e[i].length = buffer_size(&b);
2072	buffer_delete(&b);
2073
2074	/* Adjust offsets of affected entries in subpartition */
2075	offset = s->e[i].offset - offset;
2076	for (; i < s->h.num_entries; i++)
2077		s->e[i].offset += offset;
2078
2079	/* Re-calculate checksum */
2080	s->h.checksum = calc_checksum(s);
2081
2082	/* Convert members to litte-endian */
2083	subpart_dir_fixup_write_buffer(&subpart_dir_buf);
2084
2085	memcpy(dst_data, buffer_get(&subpart_dir_buf),
2086	       buffer_size(&subpart_dir_buf));
2087
2088	buffer_delete(&subpart_dir_buf);
2089
2090	printf("Sub-partition %s(%d) entry %s replaced from file %s.\n",
2091	       param.subpart_name, type, param.dentry_name, param.file_name);
2092
2093	return REPACK_REQUIRED;
2094}
2095
2096static enum ifwi_ret ifwi_replace(void)
2097{
2098	if (!param.file_name) {
2099		ERROR("%s: -f option required\n", __func__);
2100		return COMMAND_ERR;
2101	}
2102
2103	if (!param.subpart_name) {
2104		ERROR("%s: -n option required\n", __func__);
2105		return COMMAND_ERR;
2106	}
2107
2108	int type = find_type_by_name(param.subpart_name);
2109
2110	if (type == -1)
2111		return COMMAND_ERR;
2112
2113	const struct subpart_info *curr_subpart = &subparts[type];
2114
2115	if (curr_subpart->attr & AUTO_GENERATED) {
2116		ERROR("Cannot replace auto-generated sub-partitions.\n");
2117		return COMMAND_ERR;
2118	}
2119
2120	if (buffer_size(&ifwi_image.subpart_buf[type]) == 0) {
2121		ERROR("Image does not contain sub-partition %s(%d).\n",
2122		      param.subpart_name, type);
2123		return COMMAND_ERR;
2124	}
2125
2126	if (param.dir_ops)
2127		return ifwi_dir_replace(type);
2128
2129	return ifwi_raw_replace(type);
2130}
2131
2132static enum ifwi_ret ifwi_create(void)
2133{
2134	/*
2135	 * Create peels off any non-IFWI content present in the input buffer and
2136	 * creates output file with only the IFWI present.
2137	 */
2138
2139	if (!param.file_name) {
2140		ERROR("%s: -f option required\n", __func__);
2141		return COMMAND_ERR;
2142	}
2143
2144	/* Peel off any non-IFWI prefix */
2145	buffer_seek(&ifwi_image.input_buff,
2146		    ifwi_image.input_ifwi_start_offset);
2147	/* Peel off any non-IFWI suffix */
2148	buffer_set_size(&ifwi_image.input_buff,
2149			ifwi_image.input_ifwi_end_offset -
2150			ifwi_image.input_ifwi_start_offset);
2151
2152	/*
2153	 * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
2154	 */
2155	ifwi_image.input_ifwi_end_offset -= ifwi_image.input_ifwi_start_offset;
2156	ifwi_image.input_ifwi_start_offset = 0;
2157
2158	param.image_name = param.file_name;
2159
2160	return REPACK_REQUIRED;
2161}
2162
2163struct command {
2164	const char *name;
2165	const char *optstring;
2166	enum ifwi_ret (*function)(void);
2167};
2168
2169static const struct command commands[] = {
2170	{"add", "f:n:e:dvh?", ifwi_add},
2171	{"create", "f:vh?", ifwi_create},
2172	{"delete", "f:n:vh?", ifwi_delete},
2173	{"extract", "f:n:e:dvh?", ifwi_extract},
2174	{"print", "dh?", ifwi_print},
2175	{"replace", "f:n:e:dvh?", ifwi_replace},
2176};
2177
2178static struct option long_options[] = {
2179	{"subpart_dentry",  required_argument, 0, 'e'},
2180	{"file",	    required_argument, 0, 'f'},
2181	{"help",	    required_argument, 0, 'h'},
2182	{"name",	    required_argument, 0, 'n'},
2183	{"dir_ops",         no_argument,       0, 'd'},
2184	{"verbose",	    no_argument,       0, 'v'},
2185	{NULL,		    0,                 0,  0 }
2186};
2187
2188static void usage(const char *name)
2189{
2190	printf("ifwitool: Utility for IFWI manipulation\n\n"
2191	       "USAGE:\n"
2192	       " %s [-h]\n"
2193	       " %s FILE COMMAND [PARAMETERS]\n\n"
2194	       "COMMANDs:\n"
2195	       " add -f FILE -n NAME [-d -e ENTRY]\n"
2196	       " create -f FILE\n"
2197	       " delete -n NAME\n"
2198	       " extract -f FILE -n NAME [-d -e ENTRY]\n"
2199	       " print [-d]\n"
2200	       " replace -f FILE -n NAME [-d -e ENTRY]\n"
2201	       "OPTIONs:\n"
2202	       " -f FILE : File to read/write/create/extract\n"
2203	       " -d      : Perform directory operation\n"
2204	       " -e ENTRY: Name of directory entry to operate on\n"
2205	       " -v      : Verbose level\n"
2206	       " -h      : Help message\n"
2207	       " -n NAME : Name of sub-partition to operate on\n",
2208	       name, name
2209	       );
2210
2211	printf("\nNAME should be one of:\n");
2212	int i;
2213
2214	for (i = 0; i < MAX_SUBPARTS; i++)
2215		printf("%s(%s)\n", subparts[i].name, subparts[i].readable_name);
2216	printf("\n");
2217}
2218
2219int main(int argc, char **argv)
2220{
2221	if (argc < 3) {
2222		usage(argv[0]);
2223		return 1;
2224	}
2225
2226	param.image_name = argv[1];
2227	char *cmd = argv[2];
2228
2229	optind += 2;
2230
2231	uint32_t i;
2232
2233	for (i = 0; i < ARRAY_SIZE(commands); i++) {
2234		if (strcmp(cmd, commands[i].name) != 0)
2235			continue;
2236
2237		int c;
2238
2239		while (1) {
2240			int option_index;
2241
2242			c = getopt_long(argc, argv, commands[i].optstring,
2243					long_options, &option_index);
2244
2245			if (c == -1)
2246				break;
2247
2248			/* Filter out illegal long options */
2249			if (!strchr(commands[i].optstring, c)) {
2250				ERROR("%s: invalid option -- '%c'\n", argv[0],
2251				      c);
2252				c = '?';
2253			}
2254
2255			switch (c) {
2256			case 'n':
2257				param.subpart_name = optarg;
2258				break;
2259			case 'f':
2260				param.file_name = optarg;
2261				break;
2262			case 'd':
2263				param.dir_ops = 1;
2264				break;
2265			case 'e':
2266				param.dentry_name = optarg;
2267				break;
2268			case 'v':
2269				verbose++;
2270				break;
2271			case 'h':
2272			case '?':
2273				usage(argv[0]);
2274				return 1;
2275			default:
2276				break;
2277			}
2278		}
2279
2280		if (ifwi_parse()) {
2281			ERROR("%s: ifwi parsing failed\n", argv[0]);
2282			return 1;
2283		}
2284
2285		enum ifwi_ret ret = commands[i].function();
2286
2287		if (ret == COMMAND_ERR) {
2288			ERROR("%s: failed execution\n", argv[0]);
2289			return 1;
2290		}
2291
2292		if (ret == REPACK_REQUIRED)
2293			ifwi_repack();
2294
2295		return 0;
2296	}
2297
2298	ERROR("%s: invalid command\n", argv[0]);
2299	return 1;
2300}
2301