1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * ifwitool, CLI utility for Integrated Firmware Image (IFWI) manipulation
4  *
5  * This is taken from the Coreboot project
6  */
7 
8 #include <assert.h>
9 #include <stdbool.h>
10 #include <getopt.h>
11 #include "imagetool.h"
12 #include "os_support.h"
13 
14 #ifndef __packed
15 #define __packed		__attribute__((packed))
16 #endif
17 #define KiB			1024
18 
19 /*
20  * min()/max()/clamp() macros that also do
21  * strict type-checking.. See the
22  * "unnecessary" pointer comparison.
23  */
24 #define min(x, y) ({				\
25 	typeof(x) _min1 = (x);			\
26 	typeof(y) _min2 = (y);			\
27 	(void)&_min1 == &_min2);		\
28 	_min1 < _min2 ? _min1 : _min2; })
29 
30 #define max(x, y) ({				\
31 	typeof(x) _max1 = (x);			\
32 	typeof(y) _max2 = (y);			\
33 	(void)(&_max1 == &_max2);		\
34 	_max1 > _max2 ? _max1 : _max2; })
35 
36 static int verbose = 1;
37 
38 /* Buffer and file I/O */
39 struct buffer {
40 	char *name;
41 	char *data;
42 	size_t offset;
43 	size_t size;
44 };
45 
46 #define ERROR(...) { fprintf(stderr, "E: " __VA_ARGS__); }
47 #define INFO(...) { if (verbose > 0) fprintf(stderr, "INFO: " __VA_ARGS__); }
48 #define DEBUG(...) { if (verbose > 1) fprintf(stderr, "DEBUG: " __VA_ARGS__); }
49 
50 /*
51  * BPDT is Boot Partition Descriptor Table. It is located at the start of a
52  * logical boot partition(LBP). It stores information about the critical
53  * sub-partitions present within the LBP.
54  *
55  * S-BPDT is Secondary Boot Partition Descriptor Table. It is located after the
56  * critical sub-partitions and contains information about the non-critical
57  * sub-partitions present within the LBP.
58  *
59  * Both tables are identified by BPDT_SIGNATURE stored at the start of the
60  * table.
61  */
62 #define BPDT_SIGNATURE				(0x000055AA)
63 
64 /* Parameters passed in by caller */
65 static struct param {
66 	const char *file_name;
67 	const char *subpart_name;
68 	const char *image_name;
69 	bool dir_ops;
70 	const char *dentry_name;
71 } param;
72 
73 struct bpdt_header {
74 	/*
75 	 * This is used to identify start of BPDT. It should always be
76 	 * BPDT_SIGNATURE.
77 	 */
78 	uint32_t signature;
79 	/* Count of BPDT entries present */
80 	uint16_t descriptor_count;
81 	/* Version - Currently supported = 1 */
82 	uint16_t bpdt_version;
83 	/* Unused - Should be 0 */
84 	uint32_t xor_redundant_block;
85 	/* Version of IFWI build */
86 	uint32_t ifwi_version;
87 	/* Version of FIT tool used to create IFWI */
88 	uint64_t fit_tool_version;
89 } __packed;
90 #define BPDT_HEADER_SIZE			(sizeof(struct bpdt_header))
91 
92 struct bpdt_entry {
93 	/* Type of sub-partition */
94 	uint16_t type;
95 	/* Attributes of sub-partition */
96 	uint16_t flags;
97 	/* Offset of sub-partition from beginning of LBP */
98 	uint32_t offset;
99 	/* Size in bytes of sub-partition */
100 	uint32_t size;
101 } __packed;
102 #define BPDT_ENTRY_SIZE			(sizeof(struct bpdt_entry))
103 
104 struct bpdt {
105 	struct bpdt_header h;
106 	/* In practice, this could be an array of 0 to n entries */
107 	struct bpdt_entry e[0];
108 } __packed;
109 
get_bpdt_size(struct bpdt_header * h)110 static inline size_t get_bpdt_size(struct bpdt_header *h)
111 {
112 	return (sizeof(*h) + BPDT_ENTRY_SIZE * h->descriptor_count);
113 }
114 
115 /* Minimum size in bytes allocated to BPDT in IFWI */
116 #define BPDT_MIN_SIZE			((size_t)512)
117 
118 /* Header to define directory header for sub-partition */
119 struct subpart_dir_header {
120 	/* Should be SUBPART_DIR_MARKER */
121 	uint32_t marker;
122 	/* Number of directory entries in the sub-partition */
123 	uint32_t num_entries;
124 	/* Currenty supported - 1 */
125 	uint8_t header_version;
126 	/* Currenty supported - 1 */
127 	uint8_t entry_version;
128 	/* Length of directory header in bytes */
129 	uint8_t header_length;
130 	/*
131 	 * 2s complement of 8-bit sum from first byte of header to last byte of
132 	 * last directory entry.
133 	 */
134 	uint8_t checksum;
135 	/* ASCII short name of sub-partition */
136 	uint8_t name[4];
137 } __packed;
138 #define SUBPART_DIR_HEADER_SIZE			\
139 					(sizeof(struct subpart_dir_header))
140 #define SUBPART_DIR_MARKER				0x44504324
141 #define SUBPART_DIR_HEADER_VERSION_SUPPORTED	1
142 #define SUBPART_DIR_ENTRY_VERSION_SUPPORTED	1
143 
144 /* Structure for each directory entry for sub-partition */
145 struct subpart_dir_entry {
146 	/* Name of directory entry - Not guaranteed to be NULL-terminated */
147 	uint8_t name[12];
148 	/* Offset of entry from beginning of sub-partition */
149 	uint32_t offset;
150 	/* Length in bytes of sub-directory entry */
151 	uint32_t length;
152 	/* Must be zero */
153 	uint32_t rsvd;
154 } __packed;
155 #define SUBPART_DIR_ENTRY_SIZE			\
156 					(sizeof(struct subpart_dir_entry))
157 
158 struct subpart_dir {
159 	struct subpart_dir_header h;
160 	/* In practice, this could be an array of 0 to n entries */
161 	struct subpart_dir_entry e[0];
162 } __packed;
163 
subpart_dir_size(struct subpart_dir_header * h)164 static inline size_t subpart_dir_size(struct subpart_dir_header *h)
165 {
166 	return (sizeof(*h) + SUBPART_DIR_ENTRY_SIZE * h->num_entries);
167 }
168 
169 struct manifest_header {
170 	uint32_t header_type;
171 	uint32_t header_length;
172 	uint32_t header_version;
173 	uint32_t flags;
174 	uint32_t vendor;
175 	uint32_t date;
176 	uint32_t size;
177 	uint32_t id;
178 	uint32_t rsvd;
179 	uint64_t version;
180 	uint32_t svn;
181 	uint64_t rsvd1;
182 	uint8_t rsvd2[64];
183 	uint32_t modulus_size;
184 	uint32_t exponent_size;
185 	uint8_t public_key[256];
186 	uint32_t exponent;
187 	uint8_t signature[256];
188 } __packed;
189 
190 #define DWORD_SIZE				4
191 #define MANIFEST_HDR_SIZE			(sizeof(struct manifest_header))
192 #define MANIFEST_ID_MAGIC			(0x324e4d24)
193 
194 struct module {
195 	uint8_t name[12];
196 	uint8_t type;
197 	uint8_t hash_alg;
198 	uint16_t hash_size;
199 	uint32_t metadata_size;
200 	uint8_t metadata_hash[32];
201 } __packed;
202 
203 #define MODULE_SIZE				(sizeof(struct module))
204 
205 struct signed_pkg_info_ext {
206 	uint32_t ext_type;
207 	uint32_t ext_length;
208 	uint8_t name[4];
209 	uint32_t vcn;
210 	uint8_t bitmap[16];
211 	uint32_t svn;
212 	uint8_t rsvd[16];
213 } __packed;
214 
215 #define SIGNED_PKG_INFO_EXT_TYPE		0x15
216 #define SIGNED_PKG_INFO_EXT_SIZE		\
217 	(sizeof(struct signed_pkg_info_ext))
218 
219 /*
220  * Attributes for various IFWI sub-partitions.
221  * LIES_WITHIN_BPDT_4K = Sub-Partition should lie within the same 4K block as
222  * BPDT.
223  * NON_CRITICAL_SUBPART = Sub-Partition entry should be present in S-BPDT.
224  * CONTAINS_DIR = Sub-Partition contains directory.
225  * AUTO_GENERATED = Sub-Partition is generated by the tool.
226  * MANDATORY_BPDT_ENTRY = Even if sub-partition is deleted, BPDT should contain
227  * an entry for it with size 0 and offset 0.
228  */
229 enum subpart_attributes {
230 	LIES_WITHIN_BPDT_4K = (1 << 0),
231 	NON_CRITICAL_SUBPART = (1 << 1),
232 	CONTAINS_DIR = (1 << 2),
233 	AUTO_GENERATED = (1 << 3),
234 	MANDATORY_BPDT_ENTRY = (1 << 4),
235 };
236 
237 /* Type value for various IFWI sub-partitions */
238 enum bpdt_entry_type {
239 	SMIP_TYPE		= 0,
240 	CSE_RBE_TYPE		= 1,
241 	CSE_BUP_TYPE		= 2,
242 	UCODE_TYPE		= 3,
243 	IBB_TYPE		= 4,
244 	S_BPDT_TYPE		= 5,
245 	OBB_TYPE		= 6,
246 	CSE_MAIN_TYPE		= 7,
247 	ISH_TYPE		= 8,
248 	CSE_IDLM_TYPE		= 9,
249 	IFP_OVERRIDE_TYPE	= 10,
250 	DEBUG_TOKENS_TYPE	= 11,
251 	UFS_PHY_TYPE		= 12,
252 	UFS_GPP_TYPE		= 13,
253 	PMC_TYPE		= 14,
254 	IUNIT_TYPE		= 15,
255 	NVM_CONFIG_TYPE	= 16,
256 	UEP_TYPE		= 17,
257 	UFS_RATE_B_TYPE	= 18,
258 	MAX_SUBPARTS		= 19,
259 };
260 
261 /*
262  * There are two order requirements for an IFWI image:
263  * 1. Order in which the sub-partitions lie within the BPDT entries.
264  * 2. Order in which the sub-partitions lie within the image.
265  *
266  * header_order defines #1 i.e. the order in which the sub-partitions should
267  * appear in the BPDT entries. pack_order defines #2 i.e. the order in which
268  * sub-partitions appear in the IFWI image. pack_order controls the offset and
269  * thus sub-partitions would have increasing offsets as we loop over pack_order.
270  */
271 const enum bpdt_entry_type bpdt_header_order[MAX_SUBPARTS] = {
272 	/* Order of the following entries is mandatory */
273 	CSE_IDLM_TYPE,
274 	IFP_OVERRIDE_TYPE,
275 	S_BPDT_TYPE,
276 	CSE_RBE_TYPE,
277 	UFS_PHY_TYPE,
278 	UFS_GPP_TYPE,
279 	/* Order of the following entries is recommended */
280 	UEP_TYPE,
281 	NVM_CONFIG_TYPE,
282 	UFS_RATE_B_TYPE,
283 	IBB_TYPE,
284 	SMIP_TYPE,
285 	PMC_TYPE,
286 	CSE_BUP_TYPE,
287 	UCODE_TYPE,
288 	DEBUG_TOKENS_TYPE,
289 	IUNIT_TYPE,
290 	CSE_MAIN_TYPE,
291 	ISH_TYPE,
292 	OBB_TYPE,
293 };
294 
295 const enum bpdt_entry_type bpdt_pack_order[MAX_SUBPARTS] = {
296 	/* Order of the following entries is mandatory */
297 	UFS_GPP_TYPE,
298 	UFS_PHY_TYPE,
299 	IFP_OVERRIDE_TYPE,
300 	UEP_TYPE,
301 	NVM_CONFIG_TYPE,
302 	UFS_RATE_B_TYPE,
303 	/* Order of the following entries is recommended */
304 	IBB_TYPE,
305 	SMIP_TYPE,
306 	CSE_RBE_TYPE,
307 	PMC_TYPE,
308 	CSE_BUP_TYPE,
309 	UCODE_TYPE,
310 	CSE_IDLM_TYPE,
311 	DEBUG_TOKENS_TYPE,
312 	S_BPDT_TYPE,
313 	IUNIT_TYPE,
314 	CSE_MAIN_TYPE,
315 	ISH_TYPE,
316 	OBB_TYPE,
317 };
318 
319 /* Utility functions */
320 enum ifwi_ret {
321 	COMMAND_ERR = -1,
322 	NO_ACTION_REQUIRED = 0,
323 	REPACK_REQUIRED = 1,
324 };
325 
326 struct dir_ops {
327 	enum ifwi_ret (*dir_add)(int type);
328 };
329 
330 static enum ifwi_ret ibbp_dir_add(int type);
331 
332 const struct subpart_info {
333 	const char *name;
334 	const char *readable_name;
335 	uint32_t attr;
336 	struct dir_ops dir_ops;
337 } subparts[MAX_SUBPARTS] = {
338 	/* OEM SMIP */
339 	[SMIP_TYPE] = {"SMIP", "SMIP", CONTAINS_DIR, {NULL} },
340 	/* CSE RBE */
341 	[CSE_RBE_TYPE] = {"RBEP", "CSE_RBE", CONTAINS_DIR |
342 			  MANDATORY_BPDT_ENTRY, {NULL} },
343 	/* CSE BUP */
344 	[CSE_BUP_TYPE] = {"FTPR", "CSE_BUP", CONTAINS_DIR |
345 			  MANDATORY_BPDT_ENTRY, {NULL} },
346 	/* uCode */
347 	[UCODE_TYPE] = {"UCOD", "Microcode", CONTAINS_DIR, {NULL} },
348 	/* IBB */
349 	[IBB_TYPE] = {"IBBP", "Bootblock", CONTAINS_DIR, {ibbp_dir_add} },
350 	/* S-BPDT */
351 	[S_BPDT_TYPE] = {"S_BPDT", "S-BPDT", AUTO_GENERATED |
352 			 MANDATORY_BPDT_ENTRY, {NULL} },
353 	/* OBB */
354 	[OBB_TYPE] = {"OBBP", "OEM boot block", CONTAINS_DIR |
355 		      NON_CRITICAL_SUBPART, {NULL} },
356 	/* CSE Main */
357 	[CSE_MAIN_TYPE] = {"NFTP", "CSE_MAIN", CONTAINS_DIR |
358 			   NON_CRITICAL_SUBPART, {NULL} },
359 	/* ISH */
360 	[ISH_TYPE] = {"ISHP", "ISH", NON_CRITICAL_SUBPART, {NULL} },
361 	/* CSE IDLM */
362 	[CSE_IDLM_TYPE] = {"DLMP", "CSE_IDLM", CONTAINS_DIR |
363 			   MANDATORY_BPDT_ENTRY, {NULL} },
364 	/* IFP Override */
365 	[IFP_OVERRIDE_TYPE] = {"IFP_OVERRIDE", "IFP_OVERRIDE",
366 			       LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
367 			       {NULL} },
368 	/* Debug Tokens */
369 	[DEBUG_TOKENS_TYPE] = {"DEBUG_TOKENS", "Debug Tokens", 0, {NULL} },
370 	/* UFS Phy Configuration */
371 	[UFS_PHY_TYPE] = {"UFS_PHY", "UFS Phy", LIES_WITHIN_BPDT_4K |
372 			  MANDATORY_BPDT_ENTRY, {NULL} },
373 	/* UFS GPP LUN ID */
374 	[UFS_GPP_TYPE] = {"UFS_GPP", "UFS GPP", LIES_WITHIN_BPDT_4K |
375 			  MANDATORY_BPDT_ENTRY, {NULL} },
376 	/* PMC */
377 	[PMC_TYPE] = {"PMCP", "PMC firmware", CONTAINS_DIR, {NULL} },
378 	/* IUNIT */
379 	[IUNIT_TYPE] = {"IUNP", "IUNIT", NON_CRITICAL_SUBPART, {NULL} },
380 	/* NVM Config */
381 	[NVM_CONFIG_TYPE] = {"NVM_CONFIG", "NVM Config", 0, {NULL} },
382 	/* UEP */
383 	[UEP_TYPE] = {"UEP", "UEP", LIES_WITHIN_BPDT_4K | MANDATORY_BPDT_ENTRY,
384 		      {NULL} },
385 	/* UFS Rate B Config */
386 	[UFS_RATE_B_TYPE] = {"UFS_RATE_B", "UFS Rate B Config", 0, {NULL} },
387 };
388 
389 struct ifwi_image {
390 	/* Data read from input file */
391 	struct buffer input_buff;
392 
393 	/* BPDT header and entries */
394 	struct buffer bpdt;
395 	size_t input_ifwi_start_offset;
396 	size_t input_ifwi_end_offset;
397 
398 	/* Subpartition content */
399 	struct buffer subpart_buf[MAX_SUBPARTS];
400 } ifwi_image;
401 
402 /* Buffer and file I/O */
get_file_size(FILE * f)403 static off_t get_file_size(FILE *f)
404 {
405 	off_t fsize;
406 
407 	fseek(f, 0, SEEK_END);
408 	fsize = ftell(f);
409 	fseek(f, 0, SEEK_SET);
410 	return fsize;
411 }
412 
buffer_get(const struct buffer * b)413 static inline void *buffer_get(const struct buffer *b)
414 {
415 	return b->data;
416 }
417 
buffer_size(const struct buffer * b)418 static inline size_t buffer_size(const struct buffer *b)
419 {
420 	return b->size;
421 }
422 
buffer_offset(const struct buffer * b)423 static inline size_t buffer_offset(const struct buffer *b)
424 {
425 	return b->offset;
426 }
427 
428 /*
429  * Shrink a buffer toward the beginning of its previous space.
430  * Afterward, buffer_delete() remains the means of cleaning it up
431  */
buffer_set_size(struct buffer * b,size_t size)432 static inline void buffer_set_size(struct buffer *b, size_t size)
433 {
434 	b->size = size;
435 }
436 
437 /* Splice a buffer into another buffer. Note that it's up to the caller to
438  * bounds check the offset and size. The resulting buffer is backed by the same
439  * storage as the original, so although it is valid to buffer_delete() either
440  * one of them, doing so releases both simultaneously
441  */
buffer_splice(struct buffer * dest,const struct buffer * src,size_t offset,size_t size)442 static void buffer_splice(struct buffer *dest, const struct buffer *src,
443 			  size_t offset, size_t size)
444 {
445 	dest->name = src->name;
446 	dest->data = src->data + offset;
447 	dest->offset = src->offset + offset;
448 	dest->size = size;
449 }
450 
451 /*
452  * Shrink a buffer toward the end of its previous space.
453  * Afterward, buffer_delete() remains the means of cleaning it up
454  */
buffer_seek(struct buffer * b,size_t size)455 static inline void buffer_seek(struct buffer *b, size_t size)
456 {
457 	b->offset += size;
458 	b->size -= size;
459 	b->data += size;
460 }
461 
462 /* Returns the start of the underlying buffer, with the offset undone */
buffer_get_original_backing(const struct buffer * b)463 static inline void *buffer_get_original_backing(const struct buffer *b)
464 {
465 	if (!b)
466 		return NULL;
467 	return buffer_get(b) - buffer_offset(b);
468 }
469 
buffer_create(struct buffer * buffer,size_t size,const char * name)470 int buffer_create(struct buffer *buffer, size_t size, const char *name)
471 {
472 	buffer->name = strdup(name);
473 	buffer->offset = 0;
474 	buffer->size = size;
475 	buffer->data = (char *)malloc(buffer->size);
476 	if (!buffer->data) {
477 		fprintf(stderr, "%s: Insufficient memory (0x%zx).\n", __func__,
478 			size);
479 	}
480 
481 	return !buffer->data;
482 }
483 
buffer_write_file(struct buffer * buffer,const char * filename)484 int buffer_write_file(struct buffer *buffer, const char *filename)
485 {
486 	FILE *fp = fopen(filename, "wb");
487 
488 	if (!fp) {
489 		perror(filename);
490 		return -1;
491 	}
492 	assert(buffer && buffer->data);
493 	if (fwrite(buffer->data, 1, buffer->size, fp) != buffer->size) {
494 		fprintf(stderr, "incomplete write: %s\n", filename);
495 		fclose(fp);
496 		return -1;
497 	}
498 	fclose(fp);
499 	return 0;
500 }
501 
buffer_delete(struct buffer * buffer)502 void buffer_delete(struct buffer *buffer)
503 {
504 	assert(buffer);
505 	if (buffer->name) {
506 		free(buffer->name);
507 		buffer->name = NULL;
508 	}
509 	if (buffer->data) {
510 		free(buffer_get_original_backing(buffer));
511 		buffer->data = NULL;
512 	}
513 	buffer->offset = 0;
514 	buffer->size = 0;
515 }
516 
buffer_from_file(struct buffer * buffer,const char * filename)517 int buffer_from_file(struct buffer *buffer, const char *filename)
518 {
519 	FILE *fp = fopen(filename, "rb");
520 
521 	if (!fp) {
522 		perror(filename);
523 		return -1;
524 	}
525 	buffer->offset = 0;
526 	off_t file_size = get_file_size(fp);
527 
528 	if (file_size < 0) {
529 		fprintf(stderr, "could not determine size of %s\n", filename);
530 		fclose(fp);
531 		return -1;
532 	}
533 	buffer->size = file_size;
534 	buffer->name = strdup(filename);
535 	buffer->data = (char *)malloc(buffer->size);
536 	assert(buffer->data);
537 	if (fread(buffer->data, 1, buffer->size, fp) != buffer->size) {
538 		fprintf(stderr, "incomplete read: %s\n", filename);
539 		fclose(fp);
540 		buffer_delete(buffer);
541 		return -1;
542 	}
543 	fclose(fp);
544 	return 0;
545 }
546 
alloc_buffer(struct buffer * b,size_t s,const char * n)547 static void alloc_buffer(struct buffer *b, size_t s, const char *n)
548 {
549 	if (buffer_create(b, s, n) == 0)
550 		return;
551 
552 	ERROR("Buffer allocation failure for %s (size = %zx).\n", n, s);
553 	exit(-1);
554 }
555 
556 /* Little-Endian functions */
read_ble8(const void * src)557 static inline uint8_t read_ble8(const void *src)
558 {
559 	const uint8_t *s = src;
560 	return *s;
561 }
562 
read_at_ble8(const void * src,size_t offset)563 static inline uint8_t read_at_ble8(const void *src, size_t offset)
564 {
565 	const uint8_t *s = src;
566 
567 	s += offset;
568 	return read_ble8(s);
569 }
570 
write_ble8(void * dest,uint8_t val)571 static inline void write_ble8(void *dest, uint8_t val)
572 {
573 	*(uint8_t *)dest = val;
574 }
575 
write_at_ble8(void * dest,uint8_t val,size_t offset)576 static inline void write_at_ble8(void *dest, uint8_t val, size_t offset)
577 {
578 	uint8_t *d = dest;
579 
580 	d += offset;
581 	write_ble8(d, val);
582 }
583 
read_at_le8(const void * src,size_t offset)584 static inline uint8_t read_at_le8(const void *src, size_t offset)
585 {
586 	return read_at_ble8(src, offset);
587 }
588 
write_le8(void * dest,uint8_t val)589 static inline void write_le8(void *dest, uint8_t val)
590 {
591 	write_ble8(dest, val);
592 }
593 
write_at_le8(void * dest,uint8_t val,size_t offset)594 static inline void write_at_le8(void *dest, uint8_t val, size_t offset)
595 {
596 	write_at_ble8(dest, val, offset);
597 }
598 
read_le16(const void * src)599 static inline uint16_t read_le16(const void *src)
600 {
601 	const uint8_t *s = src;
602 
603 	return (((uint16_t)s[1]) << 8) | (((uint16_t)s[0]) << 0);
604 }
605 
read_at_le16(const void * src,size_t offset)606 static inline uint16_t read_at_le16(const void *src, size_t offset)
607 {
608 	const uint8_t *s = src;
609 
610 	s += offset;
611 	return read_le16(s);
612 }
613 
write_le16(void * dest,uint16_t val)614 static inline void write_le16(void *dest, uint16_t val)
615 {
616 	write_le8(dest, val >> 0);
617 	write_at_le8(dest, val >> 8, sizeof(uint8_t));
618 }
619 
write_at_le16(void * dest,uint16_t val,size_t offset)620 static inline void write_at_le16(void *dest, uint16_t val, size_t offset)
621 {
622 	uint8_t *d = dest;
623 
624 	d += offset;
625 	write_le16(d, val);
626 }
627 
read_le32(const void * src)628 static inline uint32_t read_le32(const void *src)
629 {
630 	const uint8_t *s = src;
631 
632 	return (((uint32_t)s[3]) << 24) | (((uint32_t)s[2]) << 16) |
633 		(((uint32_t)s[1]) << 8) | (((uint32_t)s[0]) << 0);
634 }
635 
read_at_le32(const void * src,size_t offset)636 static inline uint32_t read_at_le32(const void *src, size_t offset)
637 {
638 	const uint8_t *s = src;
639 
640 	s += offset;
641 	return read_le32(s);
642 }
643 
write_le32(void * dest,uint32_t val)644 static inline void write_le32(void *dest, uint32_t val)
645 {
646 	write_le16(dest, val >> 0);
647 	write_at_le16(dest, val >> 16, sizeof(uint16_t));
648 }
649 
write_at_le32(void * dest,uint32_t val,size_t offset)650 static inline void write_at_le32(void *dest, uint32_t val, size_t offset)
651 {
652 	uint8_t *d = dest;
653 
654 	d += offset;
655 	write_le32(d, val);
656 }
657 
read_le64(const void * src)658 static inline uint64_t read_le64(const void *src)
659 {
660 	uint64_t val;
661 
662 	val = read_at_le32(src, sizeof(uint32_t));
663 	val <<= 32;
664 	val |= read_le32(src);
665 	return val;
666 }
667 
read_at_le64(const void * src,size_t offset)668 static inline uint64_t read_at_le64(const void *src, size_t offset)
669 {
670 	const uint8_t *s = src;
671 
672 	s += offset;
673 	return read_le64(s);
674 }
675 
write_le64(void * dest,uint64_t val)676 static inline void write_le64(void *dest, uint64_t val)
677 {
678 	write_le32(dest, val >> 0);
679 	write_at_le32(dest, val >> 32, sizeof(uint32_t));
680 }
681 
write_at_le64(void * dest,uint64_t val,size_t offset)682 static inline void write_at_le64(void *dest, uint64_t val, size_t offset)
683 {
684 	uint8_t *d = dest;
685 
686 	d += offset;
687 	write_le64(d, val);
688 }
689 
690 /*
691  * Read header/entry members in little-endian format.
692  * Returns the offset upto which the read was performed.
693  */
read_member(void * src,size_t offset,size_t size_bytes,void * dst)694 static size_t read_member(void *src, size_t offset, size_t size_bytes,
695 			  void *dst)
696 {
697 	switch (size_bytes) {
698 	case 1:
699 		*(uint8_t *)dst = read_at_le8(src, offset);
700 		break;
701 	case 2:
702 		*(uint16_t *)dst = read_at_le16(src, offset);
703 		break;
704 	case 4:
705 		*(uint32_t *)dst = read_at_le32(src, offset);
706 		break;
707 	case 8:
708 		*(uint64_t *)dst = read_at_le64(src, offset);
709 		break;
710 	default:
711 		ERROR("Read size not supported %zd\n", size_bytes);
712 		exit(-1);
713 	}
714 
715 	return (offset + size_bytes);
716 }
717 
718 /*
719  * Convert to little endian format.
720  * Returns the offset upto which the fixup was performed.
721  */
fix_member(void * data,size_t offset,size_t size_bytes)722 static 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 
print_subpart_dir(struct subpart_dir * s)746 static void print_subpart_dir(struct subpart_dir *s)
747 {
748 	if (verbose == 0)
749 		return;
750 
751 	size_t i;
752 
753 	printf("%-25s 0x%-23.8x\n", "Marker", s->h.marker);
754 	printf("%-25s %-25d\n", "Num entries", s->h.num_entries);
755 	printf("%-25s %-25d\n", "Header Version", s->h.header_version);
756 	printf("%-25s %-25d\n", "Entry Version", s->h.entry_version);
757 	printf("%-25s 0x%-23x\n", "Header Length", s->h.header_length);
758 	printf("%-25s 0x%-23x\n", "Checksum", s->h.checksum);
759 	printf("%-25s ", "Name");
760 	for (i = 0; i < sizeof(s->h.name); i++)
761 		printf("%c", s->h.name[i]);
762 
763 	printf("\n");
764 
765 	printf("%-25s%-25s%-25s%-25s%-25s\n", "Entry #", "Name", "Offset",
766 	       "Length", "Rsvd");
767 
768 	printf("=========================================================================================================================\n");
769 
770 	for (i = 0; i < s->h.num_entries; i++) {
771 		printf("%-25zd%-25.12s0x%-23x0x%-23x0x%-23x\n", i + 1,
772 		       s->e[i].name, s->e[i].offset, s->e[i].length,
773 		       s->e[i].rsvd);
774 	}
775 
776 	printf("=========================================================================================================================\n");
777 }
778 
bpdt_print_header(struct bpdt_header * h,const char * name)779 static void bpdt_print_header(struct bpdt_header *h, const char *name)
780 {
781 	if (verbose == 0)
782 		return;
783 
784 	printf("%-25s %-25s\n", "Header", name);
785 	printf("%-25s 0x%-23.8x\n", "Signature", h->signature);
786 	printf("%-25s %-25d\n", "Descriptor count", h->descriptor_count);
787 	printf("%-25s %-25d\n", "BPDT Version", h->bpdt_version);
788 	printf("%-25s 0x%-23x\n", "XOR checksum", h->xor_redundant_block);
789 	printf("%-25s 0x%-23x\n", "IFWI Version", h->ifwi_version);
790 	printf("%-25s 0x%-23llx\n", "FIT Tool Version",
791 	       (long long)h->fit_tool_version);
792 }
793 
bpdt_print_entries(struct bpdt_entry * e,size_t count,const char * name)794 static void bpdt_print_entries(struct bpdt_entry *e, size_t count,
795 			       const char *name)
796 {
797 	size_t i;
798 
799 	if (verbose == 0)
800 		return;
801 
802 	printf("%s entries\n", name);
803 
804 	printf("%-25s%-25s%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
805 	       "Sub-Partition", "Name", "Type", "Flags", "Offset", "Size",
806 	       "File Offset");
807 
808 	printf("=========================================================================================================================================================================================================\n");
809 
810 	for (i = 0; i < count; i++) {
811 		printf("%-25zd%-25s%-25s%-25d0x%-23.08x0x%-23x0x%-23x0x%-23zx\n",
812 		       i + 1, subparts[e[i].type].name,
813 		       subparts[e[i].type].readable_name, e[i].type, e[i].flags,
814 		       e[i].offset, e[i].size,
815 		       e[i].offset + ifwi_image.input_ifwi_start_offset);
816 	}
817 
818 	printf("=========================================================================================================================================================================================================\n");
819 }
820 
bpdt_validate_header(struct bpdt_header * h,const char * name)821 static void bpdt_validate_header(struct bpdt_header *h, const char *name)
822 {
823 	assert(h->signature == BPDT_SIGNATURE);
824 
825 	if (h->bpdt_version != 1) {
826 		ERROR("Invalid header : %s\n", name);
827 		exit(-1);
828 	}
829 
830 	DEBUG("Validated header : %s\n", name);
831 }
832 
bpdt_read_header(void * data,struct bpdt_header * h,const char * name)833 static void bpdt_read_header(void *data, struct bpdt_header *h,
834 			     const char *name)
835 {
836 	size_t offset = 0;
837 
838 	offset = read_member(data, offset, sizeof(h->signature), &h->signature);
839 	offset = read_member(data, offset, sizeof(h->descriptor_count),
840 			     &h->descriptor_count);
841 	offset = read_member(data, offset, sizeof(h->bpdt_version),
842 			     &h->bpdt_version);
843 	offset = read_member(data, offset, sizeof(h->xor_redundant_block),
844 			     &h->xor_redundant_block);
845 	offset = read_member(data, offset, sizeof(h->ifwi_version),
846 			     &h->ifwi_version);
847 	read_member(data, offset, sizeof(h->fit_tool_version),
848 		    &h->fit_tool_version);
849 
850 	bpdt_validate_header(h, name);
851 	bpdt_print_header(h, name);
852 }
853 
bpdt_read_entries(void * data,struct bpdt * bpdt,const char * name)854 static void bpdt_read_entries(void *data, struct bpdt *bpdt, const char *name)
855 {
856 	size_t i, offset = 0;
857 	struct bpdt_entry *e = &bpdt->e[0];
858 	size_t count = bpdt->h.descriptor_count;
859 
860 	for (i = 0; i < count; i++) {
861 		offset = read_member(data, offset, sizeof(e[i].type),
862 				     &e[i].type);
863 		offset = read_member(data, offset, sizeof(e[i].flags),
864 				     &e[i].flags);
865 		offset = read_member(data, offset, sizeof(e[i].offset),
866 				     &e[i].offset);
867 		offset = read_member(data, offset, sizeof(e[i].size),
868 				     &e[i].size);
869 	}
870 
871 	bpdt_print_entries(e, count, name);
872 }
873 
874 /*
875  * Given type of sub-partition, identify BPDT entry for it.
876  * Sub-Partition could lie either within BPDT or S-BPDT.
877  */
__find_entry_by_type(struct bpdt_entry * e,size_t count,int type)878 static struct bpdt_entry *__find_entry_by_type(struct bpdt_entry *e,
879 					       size_t count, int type)
880 {
881 	size_t i;
882 
883 	for (i = 0; i < count; i++) {
884 		if (e[i].type == type)
885 			break;
886 	}
887 
888 	if (i == count)
889 		return NULL;
890 
891 	return &e[i];
892 }
893 
find_entry_by_type(int type)894 static struct bpdt_entry *find_entry_by_type(int type)
895 {
896 	struct bpdt *b = buffer_get(&ifwi_image.bpdt);
897 
898 	if (!b)
899 		return NULL;
900 
901 	struct bpdt_entry *curr = __find_entry_by_type(&b->e[0],
902 						       b->h.descriptor_count,
903 						       type);
904 
905 	if (curr)
906 		return curr;
907 
908 	b = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
909 	if (!b)
910 		return NULL;
911 
912 	return __find_entry_by_type(&b->e[0], b->h.descriptor_count, type);
913 }
914 
915 /*
916  * Find sub-partition type given its name. If the name does not exist, returns
917  * -1.
918  */
find_type_by_name(const char * name)919 static int find_type_by_name(const char *name)
920 {
921 	int i;
922 
923 	for (i = 0; i < MAX_SUBPARTS; i++) {
924 		if ((strlen(subparts[i].name) == strlen(name)) &&
925 		    (!strcmp(subparts[i].name, name)))
926 			break;
927 	}
928 
929 	if (i == MAX_SUBPARTS) {
930 		ERROR("Invalid sub-partition name %s.\n", name);
931 		return -1;
932 	}
933 
934 	return i;
935 }
936 
937 /*
938  * Read the content of a sub-partition from input file and store it in
939  * ifwi_image.subpart_buf[SUB-PARTITION_TYPE].
940  *
941  * Returns the maximum offset occupied by the sub-partitions.
942  */
read_subpart_buf(void * data,size_t size,struct bpdt_entry * e,size_t count)943 static size_t read_subpart_buf(void *data, size_t size, struct bpdt_entry *e,
944 			       size_t count)
945 {
946 	size_t i, type;
947 	struct buffer *buf;
948 	size_t max_offset = 0;
949 
950 	for (i = 0; i < count; i++) {
951 		type = e[i].type;
952 
953 		if (type >= MAX_SUBPARTS) {
954 			ERROR("Invalid sub-partition type %zd.\n", type);
955 			exit(-1);
956 		}
957 
958 		if (buffer_size(&ifwi_image.subpart_buf[type])) {
959 			ERROR("Multiple sub-partitions of type %zd(%s).\n",
960 			      type, subparts[type].name);
961 			exit(-1);
962 		}
963 
964 		if (e[i].size == 0) {
965 			INFO("Dummy sub-partition %zd(%s). Skipping.\n", type,
966 			     subparts[type].name);
967 			continue;
968 		}
969 
970 		assert((e[i].offset + e[i].size) <= size);
971 
972 		/*
973 		 * Sub-partitions in IFWI image are not in the same order as
974 		 * in BPDT entries. BPDT entires are in header_order whereas
975 		 * sub-partition offsets in the image are in pack_order.
976 		 */
977 		if ((e[i].offset + e[i].size) > max_offset)
978 			max_offset = e[i].offset + e[i].size;
979 
980 		/*
981 		 * S-BPDT sub-partition contains information about all the
982 		 * non-critical sub-partitions. Thus, size of S-BPDT
983 		 * sub-partition equals size of S-BPDT plus size of all the
984 		 * non-critical sub-partitions. Thus, reading whole of S-BPDT
985 		 * here would be redundant as the non-critical partitions are
986 		 * read and allocated buffers separately. Also, S-BPDT requires
987 		 * special handling for reading header and entries.
988 		 */
989 		if (type == S_BPDT_TYPE)
990 			continue;
991 
992 		buf = &ifwi_image.subpart_buf[type];
993 
994 		alloc_buffer(buf, e[i].size, subparts[type].name);
995 		memcpy(buffer_get(buf), (uint8_t *)data + e[i].offset,
996 		       e[i].size);
997 	}
998 
999 	assert(max_offset);
1000 	return max_offset;
1001 }
1002 
1003 /*
1004  * Allocate buffer for bpdt header, entries and all sub-partition content.
1005  * Returns offset in data where BPDT ends.
1006  */
alloc_bpdt_buffer(void * data,size_t size,size_t offset,struct buffer * b,const char * name)1007 static size_t alloc_bpdt_buffer(void *data, size_t size, size_t offset,
1008 				struct buffer *b, const char *name)
1009 {
1010 	struct bpdt_header bpdt_header;
1011 
1012 	assert((offset + BPDT_HEADER_SIZE) < size);
1013 	bpdt_read_header((uint8_t *)data + offset, &bpdt_header, name);
1014 
1015 	/* Buffer to read BPDT header and entries */
1016 	alloc_buffer(b, get_bpdt_size(&bpdt_header), name);
1017 
1018 	struct bpdt *bpdt = buffer_get(b);
1019 
1020 	memcpy(&bpdt->h, &bpdt_header, BPDT_HEADER_SIZE);
1021 
1022 	/*
1023 	 * If no entries are present, maximum offset occupied is (offset +
1024 	 * BPDT_HEADER_SIZE).
1025 	 */
1026 	if (bpdt->h.descriptor_count == 0)
1027 		return (offset + BPDT_HEADER_SIZE);
1028 
1029 	/* Read all entries */
1030 	assert((offset + get_bpdt_size(&bpdt->h)) < size);
1031 	bpdt_read_entries((uint8_t *)data + offset + BPDT_HEADER_SIZE, bpdt,
1032 			  name);
1033 
1034 	/* Read all sub-partition content in subpart_buf */
1035 	return read_subpart_buf(data, size, &bpdt->e[0],
1036 				bpdt->h.descriptor_count);
1037 }
1038 
parse_sbpdt(void * data,size_t size)1039 static void parse_sbpdt(void *data, size_t size)
1040 {
1041 	struct bpdt_entry *s;
1042 
1043 	s  = find_entry_by_type(S_BPDT_TYPE);
1044 	if (!s)
1045 		return;
1046 
1047 	assert(size > s->offset);
1048 
1049 	alloc_bpdt_buffer(data, size, s->offset,
1050 			  &ifwi_image.subpart_buf[S_BPDT_TYPE],
1051 			  "S-BPDT");
1052 }
1053 
calc_checksum(struct subpart_dir * s)1054 static uint8_t calc_checksum(struct subpart_dir *s)
1055 {
1056 	size_t size = subpart_dir_size(&s->h);
1057 	uint8_t *data = (uint8_t *)s;
1058 	uint8_t checksum = 0;
1059 	size_t i;
1060 	uint8_t old_checksum = s->h.checksum;
1061 
1062 	s->h.checksum = 0;
1063 
1064 	for (i = 0; i < size; i++)
1065 		checksum += data[i];
1066 
1067 	s->h.checksum = old_checksum;
1068 
1069 	/* 2s complement */
1070 	return -checksum;
1071 }
1072 
validate_subpart_dir(struct subpart_dir * s,const char * name,bool checksum_check)1073 static void validate_subpart_dir(struct subpart_dir *s, const char *name,
1074 				 bool checksum_check)
1075 {
1076 	if (s->h.marker != SUBPART_DIR_MARKER ||
1077 	    s->h.header_version != SUBPART_DIR_HEADER_VERSION_SUPPORTED ||
1078 	    s->h.entry_version != SUBPART_DIR_ENTRY_VERSION_SUPPORTED ||
1079 	    s->h.header_length != SUBPART_DIR_HEADER_SIZE) {
1080 		ERROR("Invalid subpart_dir for %s.\n", name);
1081 		exit(-1);
1082 	}
1083 
1084 	if (!checksum_check)
1085 		return;
1086 
1087 	uint8_t checksum = calc_checksum(s);
1088 
1089 	if (checksum != s->h.checksum)
1090 		ERROR("Invalid checksum for %s (Expected=0x%x, Actual=0x%x).\n",
1091 		      name, checksum, s->h.checksum);
1092 }
1093 
validate_subpart_dir_without_checksum(struct subpart_dir * s,const char * name)1094 static void validate_subpart_dir_without_checksum(struct subpart_dir *s,
1095 						  const char *name)
1096 {
1097 	validate_subpart_dir(s, name, 0);
1098 }
1099 
validate_subpart_dir_with_checksum(struct subpart_dir * s,const char * name)1100 static void validate_subpart_dir_with_checksum(struct subpart_dir *s,
1101 					       const char *name)
1102 {
1103 	validate_subpart_dir(s, name, 1);
1104 }
1105 
parse_subpart_dir(struct buffer * subpart_dir_buf,struct buffer * input_buf,const char * name)1106 static void parse_subpart_dir(struct buffer *subpart_dir_buf,
1107 			      struct buffer *input_buf, const char *name)
1108 {
1109 	struct subpart_dir_header hdr;
1110 	size_t offset = 0;
1111 	uint8_t *data = buffer_get(input_buf);
1112 	size_t size = buffer_size(input_buf);
1113 
1114 	/* Read Subpart_Dir header */
1115 	assert(size >= SUBPART_DIR_HEADER_SIZE);
1116 	offset = read_member(data, offset, sizeof(hdr.marker), &hdr.marker);
1117 	offset = read_member(data, offset, sizeof(hdr.num_entries),
1118 			     &hdr.num_entries);
1119 	offset = read_member(data, offset, sizeof(hdr.header_version),
1120 			     &hdr.header_version);
1121 	offset = read_member(data, offset, sizeof(hdr.entry_version),
1122 			     &hdr.entry_version);
1123 	offset = read_member(data, offset, sizeof(hdr.header_length),
1124 			     &hdr.header_length);
1125 	offset = read_member(data, offset, sizeof(hdr.checksum), &hdr.checksum);
1126 	memcpy(hdr.name, data + offset, sizeof(hdr.name));
1127 	offset += sizeof(hdr.name);
1128 
1129 	validate_subpart_dir_without_checksum((struct subpart_dir *)&hdr, name);
1130 
1131 	assert(size > subpart_dir_size(&hdr));
1132 	alloc_buffer(subpart_dir_buf, subpart_dir_size(&hdr), "Subpart Dir");
1133 	memcpy(buffer_get(subpart_dir_buf), &hdr, SUBPART_DIR_HEADER_SIZE);
1134 
1135 	/* Read Subpart Dir entries */
1136 	struct subpart_dir *subpart_dir = buffer_get(subpart_dir_buf);
1137 	struct subpart_dir_entry *e = &subpart_dir->e[0];
1138 	uint32_t i;
1139 
1140 	for (i = 0; i < hdr.num_entries; i++) {
1141 		memcpy(e[i].name, data + offset, sizeof(e[i].name));
1142 		offset += sizeof(e[i].name);
1143 		offset = read_member(data, offset, sizeof(e[i].offset),
1144 				     &e[i].offset);
1145 		offset = read_member(data, offset, sizeof(e[i].length),
1146 				     &e[i].length);
1147 		offset = read_member(data, offset, sizeof(e[i].rsvd),
1148 				     &e[i].rsvd);
1149 	}
1150 
1151 	validate_subpart_dir_with_checksum(subpart_dir, name);
1152 
1153 	print_subpart_dir(subpart_dir);
1154 }
1155 
1156 /* Parse input image file to identify different sub-partitions */
ifwi_parse(void)1157 static int ifwi_parse(void)
1158 {
1159 	struct buffer *buff = &ifwi_image.input_buff;
1160 	const char *image_name = param.image_name;
1161 
1162 	DEBUG("Parsing IFWI image...\n");
1163 
1164 	/* Read input file */
1165 	if (buffer_from_file(buff, image_name)) {
1166 		ERROR("Failed to read input file %s.\n", image_name);
1167 		return -1;
1168 	}
1169 
1170 	INFO("Buffer %p size 0x%zx\n", buff->data, buff->size);
1171 
1172 	/* Look for BPDT signature at 4K intervals */
1173 	size_t offset = 0;
1174 	void *data = buffer_get(buff);
1175 
1176 	while (offset < buffer_size(buff)) {
1177 		if (read_at_le32(data, offset) == BPDT_SIGNATURE)
1178 			break;
1179 		offset += 4 * KiB;
1180 	}
1181 
1182 	if (offset >= buffer_size(buff)) {
1183 		ERROR("Image does not contain BPDT!!\n");
1184 		return -1;
1185 	}
1186 
1187 	ifwi_image.input_ifwi_start_offset = offset;
1188 	INFO("BPDT starts at offset 0x%zx.\n", offset);
1189 
1190 	data = (uint8_t *)data + offset;
1191 	size_t ifwi_size = buffer_size(buff) - offset;
1192 
1193 	/* Read BPDT and sub-partitions */
1194 	uintptr_t end_offset;
1195 
1196 	end_offset = ifwi_image.input_ifwi_start_offset +
1197 		alloc_bpdt_buffer(data, ifwi_size, 0, &ifwi_image.bpdt, "BPDT");
1198 
1199 	/* Parse S-BPDT, if any */
1200 	parse_sbpdt(data, ifwi_size);
1201 
1202 	/*
1203 	 * Store end offset of IFWI. Required for copying any trailing non-IFWI
1204 	 * part of the image.
1205 	 * ASSUMPTION: IFWI image always ends on a 4K boundary.
1206 	 */
1207 	ifwi_image.input_ifwi_end_offset = ALIGN(end_offset, 4 * KiB);
1208 	DEBUG("Parsing done.\n");
1209 
1210 	return 0;
1211 }
1212 
1213 /*
1214  * This function is used by repack to count the number of BPDT and S-BPDT
1215  * entries that are present. It frees the current buffers used by the entries
1216  * and allocates fresh buffers that can be used for repacking. Returns BPDT
1217  * entries which are empty and need to be filled in.
1218  */
__bpdt_reset(struct buffer * b,size_t count,size_t size)1219 static void __bpdt_reset(struct buffer *b, size_t count, size_t size)
1220 {
1221 	size_t bpdt_size = BPDT_HEADER_SIZE + count * BPDT_ENTRY_SIZE;
1222 
1223 	assert(size >= bpdt_size);
1224 
1225 	/*
1226 	 * If buffer does not have the required size, allocate a fresh buffer.
1227 	 */
1228 	if (buffer_size(b) != size) {
1229 		struct buffer temp;
1230 
1231 		alloc_buffer(&temp, size, b->name);
1232 		memcpy(buffer_get(&temp), buffer_get(b), buffer_size(b));
1233 		buffer_delete(b);
1234 		*b = temp;
1235 	}
1236 
1237 	struct bpdt *bpdt = buffer_get(b);
1238 	uint8_t *ptr = (uint8_t *)&bpdt->e[0];
1239 	size_t entries_size = BPDT_ENTRY_SIZE * count;
1240 
1241 	/* Zero out BPDT entries */
1242 	memset(ptr, 0, entries_size);
1243 	/* Fill any pad-space with FF */
1244 	memset(ptr + entries_size, 0xFF, size - bpdt_size);
1245 
1246 	bpdt->h.descriptor_count = count;
1247 }
1248 
bpdt_reset(void)1249 static void bpdt_reset(void)
1250 {
1251 	size_t i;
1252 	size_t bpdt_count = 0, sbpdt_count = 0, dummy_bpdt_count = 0;
1253 
1254 	/* Count number of BPDT and S-BPDT entries */
1255 	for (i = 0; i < MAX_SUBPARTS; i++) {
1256 		if (buffer_size(&ifwi_image.subpart_buf[i]) == 0) {
1257 			if (subparts[i].attr & MANDATORY_BPDT_ENTRY) {
1258 				bpdt_count++;
1259 				dummy_bpdt_count++;
1260 			}
1261 			continue;
1262 		}
1263 
1264 		if (subparts[i].attr & NON_CRITICAL_SUBPART)
1265 			sbpdt_count++;
1266 		else
1267 			bpdt_count++;
1268 	}
1269 
1270 	DEBUG("Count: BPDT = %zd, Dummy BPDT = %zd, S-BPDT = %zd\n", bpdt_count,
1271 	      dummy_bpdt_count, sbpdt_count);
1272 
1273 	/* Update BPDT if required */
1274 	size_t bpdt_size = max(BPDT_MIN_SIZE,
1275 			       BPDT_HEADER_SIZE + bpdt_count * BPDT_ENTRY_SIZE);
1276 	__bpdt_reset(&ifwi_image.bpdt, bpdt_count, bpdt_size);
1277 
1278 	/* Update S-BPDT if required */
1279 	bpdt_size = ALIGN(BPDT_HEADER_SIZE + sbpdt_count * BPDT_ENTRY_SIZE,
1280 			  4 * KiB);
1281 	__bpdt_reset(&ifwi_image.subpart_buf[S_BPDT_TYPE], sbpdt_count,
1282 		     bpdt_size);
1283 }
1284 
1285 /* Initialize BPDT entries in header order */
bpdt_entries_init_header_order(void)1286 static void bpdt_entries_init_header_order(void)
1287 {
1288 	int i, type;
1289 	size_t size;
1290 
1291 	struct bpdt *bpdt, *sbpdt, *curr;
1292 	size_t bpdt_curr = 0, sbpdt_curr = 0, *count_ptr;
1293 
1294 	bpdt = buffer_get(&ifwi_image.bpdt);
1295 	sbpdt = buffer_get(&ifwi_image.subpart_buf[S_BPDT_TYPE]);
1296 
1297 	for (i = 0; i < MAX_SUBPARTS; i++) {
1298 		type = bpdt_header_order[i];
1299 		size = buffer_size(&ifwi_image.subpart_buf[type]);
1300 
1301 		if (size == 0 && !(subparts[type].attr & MANDATORY_BPDT_ENTRY))
1302 			continue;
1303 
1304 		if (subparts[type].attr & NON_CRITICAL_SUBPART) {
1305 			curr = sbpdt;
1306 			count_ptr = &sbpdt_curr;
1307 		} else {
1308 			curr = bpdt;
1309 			count_ptr = &bpdt_curr;
1310 		}
1311 
1312 		assert(*count_ptr < curr->h.descriptor_count);
1313 		curr->e[*count_ptr].type = type;
1314 		curr->e[*count_ptr].flags = 0;
1315 		curr->e[*count_ptr].offset = 0;
1316 		curr->e[*count_ptr].size = size;
1317 
1318 		(*count_ptr)++;
1319 	}
1320 }
1321 
pad_buffer(struct buffer * b,size_t size)1322 static void pad_buffer(struct buffer *b, size_t size)
1323 {
1324 	size_t buff_size = buffer_size(b);
1325 
1326 	assert(buff_size <= size);
1327 
1328 	if (buff_size == size)
1329 		return;
1330 
1331 	struct buffer temp;
1332 
1333 	alloc_buffer(&temp, size, b->name);
1334 	uint8_t *data = buffer_get(&temp);
1335 
1336 	memcpy(data, buffer_get(b), buff_size);
1337 	memset(data + buff_size, 0xFF, size - buff_size);
1338 
1339 	*b = temp;
1340 }
1341 
1342 /* Initialize offsets of entries using pack order */
bpdt_entries_init_pack_order(void)1343 static void bpdt_entries_init_pack_order(void)
1344 {
1345 	int i, type;
1346 	struct bpdt_entry *curr;
1347 	size_t curr_offset, curr_end;
1348 
1349 	curr_offset = max(BPDT_MIN_SIZE, buffer_size(&ifwi_image.bpdt));
1350 
1351 	/*
1352 	 * There are two types of sub-partitions that need to be handled here:
1353 	 *   1. Sub-partitions that lie within the same 4K as BPDT
1354 	 *   2. Sub-partitions that lie outside the 4K of BPDT
1355 	 *
1356 	 * For sub-partitions of type # 1, there is no requirement on the start
1357 	 * or end of the sub-partition. They need to be packed in without any
1358 	 * holes left in between. If there is any empty space left after the end
1359 	 * of the last sub-partition in 4K of BPDT, then that space needs to be
1360 	 * padded with FF bytes, but the size of the last sub-partition remains
1361 	 * unchanged.
1362 	 *
1363 	 * For sub-partitions of type # 2, both the start and end should be a
1364 	 * multiple of 4K. If not, then it needs to be padded with FF bytes and
1365 	 * size adjusted such that the sub-partition ends on 4K boundary.
1366 	 */
1367 
1368 	/* #1 Sub-partitions that lie within same 4K as BPDT */
1369 	struct buffer *last_bpdt_buff = &ifwi_image.bpdt;
1370 
1371 	for (i = 0; i < MAX_SUBPARTS; i++) {
1372 		type = bpdt_pack_order[i];
1373 		curr = find_entry_by_type(type);
1374 
1375 		if (!curr || curr->size == 0)
1376 			continue;
1377 
1378 		if (!(subparts[type].attr & LIES_WITHIN_BPDT_4K))
1379 			continue;
1380 
1381 		curr->offset = curr_offset;
1382 		curr_offset = curr->offset + curr->size;
1383 		last_bpdt_buff = &ifwi_image.subpart_buf[type];
1384 		DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
1385 		      type, curr_offset, curr->offset, curr->size,
1386 		      buffer_size(&ifwi_image.subpart_buf[type]));
1387 	}
1388 
1389 	/* Pad ff bytes if there is any empty space left in BPDT 4K */
1390 	curr_end = ALIGN(curr_offset, 4 * KiB);
1391 	pad_buffer(last_bpdt_buff,
1392 		   buffer_size(last_bpdt_buff) + (curr_end - curr_offset));
1393 	curr_offset = curr_end;
1394 
1395 	/* #2 Sub-partitions that lie outside of BPDT 4K */
1396 	for (i = 0; i < MAX_SUBPARTS; i++) {
1397 		type = bpdt_pack_order[i];
1398 		curr = find_entry_by_type(type);
1399 
1400 		if (!curr || curr->size == 0)
1401 			continue;
1402 
1403 		if (subparts[type].attr & LIES_WITHIN_BPDT_4K)
1404 			continue;
1405 
1406 		assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1407 		curr->offset = curr_offset;
1408 		curr_end = ALIGN(curr->offset + curr->size, 4 * KiB);
1409 		curr->size = curr_end - curr->offset;
1410 
1411 		pad_buffer(&ifwi_image.subpart_buf[type], curr->size);
1412 
1413 		curr_offset = curr_end;
1414 		DEBUG("type=%d, curr_offset=0x%zx, curr->offset=0x%x, curr->size=0x%x, buff_size=0x%zx\n",
1415 		      type, curr_offset, curr->offset, curr->size,
1416 		      buffer_size(&ifwi_image.subpart_buf[type]));
1417 	}
1418 
1419 	/*
1420 	 * Update size of S-BPDT to include size of all non-critical
1421 	 * sub-partitions.
1422 	 *
1423 	 * Assumption: S-BPDT always lies at the end of IFWI image.
1424 	 */
1425 	curr = find_entry_by_type(S_BPDT_TYPE);
1426 	assert(curr);
1427 
1428 	assert(curr_offset == ALIGN(curr_offset, 4 * KiB));
1429 	curr->size = curr_offset - curr->offset;
1430 }
1431 
1432 /* Convert all members of BPDT to little-endian format */
bpdt_fixup_write_buffer(struct buffer * buf)1433 static void bpdt_fixup_write_buffer(struct buffer *buf)
1434 {
1435 	struct bpdt *s = buffer_get(buf);
1436 
1437 	struct bpdt_header *h = &s->h;
1438 	struct bpdt_entry *e = &s->e[0];
1439 
1440 	size_t count = h->descriptor_count;
1441 
1442 	size_t offset = 0;
1443 
1444 	offset = fix_member(&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 /* Write BPDT to output buffer after fixup */
bpdt_write(struct buffer * dst,size_t offset,struct buffer * src)1465 static 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  * Follows these steps to re-create image:
1473  * 1. Write any non-IFWI prefix.
1474  * 2. Write out BPDT header and entries.
1475  * 3. Write sub-partition buffers to respective offsets.
1476  * 4. Write any non-IFWI suffix.
1477  *
1478  * While performing the above steps, make sure that any empty holes are filled
1479  * with FF.
1480  */
ifwi_write(const char * image_name)1481 static 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 	/* Copy non-IFWI prefix, if any */
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 	/* Copy sub-partitions using pack_order */
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 	/* Copy non-IFWI suffix, if any */
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 	 * Convert BPDT to little-endian format and write it to output buffer.
1553 	 * S-BPDT is written first and then BPDT.
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  * Calculate size and offset of each sub-partition again since it might have
1569  * changed because of add/delete operation. Also, re-create BPDT and S-BPDT
1570  * entries and write back the new IFWI image to file.
1571  */
ifwi_repack(void)1572 static 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 
init_subpart_dir_header(struct subpart_dir_header * hdr,size_t count,const char * name)1589 static 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 
init_subpart_dir_entry(struct subpart_dir_entry * e,struct buffer * b,size_t offset)1602 static 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 
init_manifest_header(struct manifest_header * hdr,size_t size)1615 static 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 
init_signed_pkg_info_ext(struct signed_pkg_info_ext * ext,size_t count,const char * name)1639 static 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 
subpart_dir_fixup_write_buffer(struct buffer * buf)1649 static 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 
create_subpart(struct buffer * dst,struct buffer * info[],size_t count,const char * name)1679 static 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 
ibbp_dir_add(int type)1720 static 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 	 * Entry # 1 - IBBP.man
1733 	 * Contains manifest header and signed pkg info extension.
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 	/* Entry # 2 - IBBL */
1748 	if (buffer_from_file(&ibbl, param.file_name))
1749 		return COMMAND_ERR;
1750 
1751 	/* Entry # 3 - IBB */
1752 	alloc_buffer(&ibb, DUMMY_IBB_SIZE, "IBB");
1753 	memset(buffer_get(&ibb), 0xFF, DUMMY_IBB_SIZE);
1754 
1755 	/* Create subpartition */
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 
ifwi_raw_add(int type)1765 static 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 
ifwi_dir_add(int type)1775 static 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 
ifwi_add(void)1801 static 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 
ifwi_delete(void)1837 static 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 
ifwi_dir_extract(int type)1867 static 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 
ifwi_raw_extract(int type)1916 static 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 
ifwi_extract(void)1927 static 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 
ifwi_print(void)1963 static 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 
ifwi_raw_replace(int type)1999 static 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 
ifwi_dir_replace(int type)2005 static 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 	/* Copy data before the sub-partition entry */
2057 	memcpy(dst_data + curr_offset, src_data, subpart_start);
2058 	curr_offset += subpart_start;
2059 
2060 	/* Copy sub-partition entry */
2061 	memcpy(dst_data + curr_offset, buffer_get(&b), buffer_size(&b));
2062 	curr_offset += buffer_size(&b);
2063 
2064 	/* Copy remaining data */
2065 	memcpy(dst_data + curr_offset, src_data + subpart_end,
2066 	       buffer_size(&ifwi_image.subpart_buf[type]) - subpart_end);
2067 
2068 	/* Update sub-partition buffer */
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 	/* Update length of entry in the subpartition */
2075 	s->e[i].length = buffer_size(&b);
2076 	buffer_delete(&b);
2077 
2078 	/* Adjust offsets of affected entries in subpartition */
2079 	offset = s->e[i].offset - offset;
2080 	for (; i < s->h.num_entries; i++)
2081 		s->e[i].offset += offset;
2082 
2083 	/* Re-calculate checksum */
2084 	s->h.checksum = calc_checksum(s);
2085 
2086 	/* Convert members to litte-endian */
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 
ifwi_replace(void)2100 static 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 
ifwi_create(void)2136 static enum ifwi_ret ifwi_create(void)
2137 {
2138 	/*
2139 	 * Create peels off any non-IFWI content present in the input buffer and
2140 	 * creates output file with only the IFWI present.
2141 	 */
2142 
2143 	if (!param.file_name) {
2144 		ERROR("%s: -f option required\n", __func__);
2145 		return COMMAND_ERR;
2146 	}
2147 
2148 	/* Peel off any non-IFWI prefix */
2149 	buffer_seek(&ifwi_image.input_buff,
2150 		    ifwi_image.input_ifwi_start_offset);
2151 	/* Peel off any non-IFWI suffix */
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 	 * Adjust start and end offset of IFWI now that non-IFWI prefix is gone.
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 
2167 struct command {
2168 	const char *name;
2169 	const char *optstring;
2170 	enum ifwi_ret (*function)(void);
2171 };
2172 
2173 static 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 
2182 static 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 
usage(const char * name)2192 static 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 
main(int argc,char ** argv)2223 int 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 			/* Filter out illegal long options */
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