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