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