xref: /aosp_15_r20/external/coreboot/util/cbfstool/cse_serger.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /* CSE Serger - Tool for stitching Intel CSE components */
3 
4 #include <errno.h>
5 #include <getopt.h>
6 #include <stdlib.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <time.h>
10 #include <unistd.h>
11 
12 #include "cse_serger.h"
13 
14 #define NO_PARTITION_TYPE	(-1)
15 
16 static struct params {
17 	bool print_sub_parts;
18 	const char *partition_name;
19 	int partition_type;
20 	const char *output_dir;
21 	const char *image_name;
22 	const char *version_str;
23 	const char *input_file;
24 	struct region layout_regions[BP_TOTAL];
25 	const char *layout_files[BP_TOTAL];
26 } params;
27 
28 static const struct {
29 	const char *version_str;
30 	const struct bpdt_ops *ops;
31 } bpdt_ops_table[] = {
32 	{ "1.6", &bpdt_1_6_ops },
33 	{ "1.7", &bpdt_1_7_ops },
34 };
35 
36 static const struct {
37 	enum subpart_hdr_version version;
38 	const struct subpart_hdr_ops *ops;
39 } subpart_hdr_ops_table[] = {
40 	{ SUBPART_HDR_VERSION_1, &subpart_hdr_1_ops },
41 	{ SUBPART_HDR_VERSION_2, &subpart_hdr_2_ops },
42 };
43 
44 static const struct {
45 	enum subpart_entry_version version;
46 	const struct subpart_entry_ops *ops;
47 } subpart_entry_ops_table[] = {
48 	{ SUBPART_ENTRY_VERSION_1, &subpart_entry_1_ops },
49 };
50 
51 enum bpdt_entry_type {
52 	SMIP = 0,
53 	CSE_RBE = 1,
54 	CSE_BUP = 2,
55 	UCODE = 3,
56 	IBB = 4,
57 	S_BPDT = 5,
58 	OBB = 6,
59 	CSE_MAIN = 7,
60 	ISH = 8,
61 	CSE_IDLM = 9,
62 	IFP_OVERRIDE = 10,
63 	UTOK = 11,
64 	UFS_PHY = 12,
65 	UFS_GPP = 13,
66 	PMC = 14,
67 	IUNIT = 15,
68 	NVM_CFG = 16,
69 	UEP = 17,
70 	OEM_KM = 20,
71 	PAVP = 22,
72 	IOM_FW = 23,
73 	NPHY_FW = 24,
74 	TBT_FW = 25,
75 	ICC = 32,
76 
77 	MAX_SUBPARTS,
78 };
79 
80 static struct {
81 	struct buffer input_buff;
82 
83 	const struct bpdt_ops *bpdt_ops;
84 	const struct subpart_hdr_ops *subpart_hdr_ops;
85 	const struct subpart_entry_ops *subpart_entry_ops;
86 
87 	bpdt_hdr_ptr bpdt_hdr;
88 	cse_layout_ptr cse_layout;
89 	struct bpdt_entry bpdt_entries[MAX_SUBPARTS];
90 	struct buffer subpart_buff[MAX_SUBPARTS];
91 	bool repack;
92 	size_t file_end_offset;
93 } ifwi;
94 
95 #define SUBPART_WITH_ALT(_index, _rname, _name, _aname)	\
96 				[_index] = { _rname, _name, _aname }
97 #define SUBPART(_index, _rname, _name)				\
98 				SUBPART_WITH_ALT(_index, _rname, _name, "")
99 
100 static const struct {
101 	const char *readable_name;
102 	const char *name;
103 	const char *alt_name;
104 } subparts[] = {
105 	SUBPART(SMIP, "OEM SMIP", "SMIP"),
106 	SUBPART(CSE_RBE, "CSE RBE", "RBEP"),
107 	SUBPART_WITH_ALT(CSE_BUP, "CSE BUP", "FTPR", "MFTP"),
108 	SUBPART(UCODE, "Microcode", "UCOD"),
109 	SUBPART(IBB, "Initial Boot Block", "IBBP"),
110 	SUBPART(S_BPDT, "Secondary BPDT", "SBDT"),
111 	SUBPART(OBB, "OEM Boot Block", "OBBP"),
112 	SUBPART(CSE_MAIN, "CSE Main", "NFTP"),
113 	SUBPART(ISH, "ISH Firmware", "ISHP"),
114 	SUBPART(CSE_IDLM, "CSE IDLM", "DLMP"),
115 	SUBPART(IFP_OVERRIDE, "IFP override", "IFPP"),
116 	SUBPART(UTOK, "Debug tokens", "UTOK"),
117 	SUBPART(UFS_PHY, "UFS Phy", "UFSP"),
118 	SUBPART(UFS_GPP, "UFS GPP", "UFSG"),
119 	SUBPART(PMC, "PMC Firmware", "PMCP"),
120 	SUBPART(IUNIT, "IUNIT Firmware", "IUNP"),
121 	SUBPART(NVM_CFG, "NVM CFG", "NVMC"),
122 	SUBPART(UEP, "UEP", "UEPP"),
123 	SUBPART(OEM_KM, "OEM Key Manifest", "OEMP"),
124 	SUBPART(PAVP, "PAVP", "PAVP"),
125 	SUBPART(IOM_FW, "IOM Firmware", "IOMP"),
126 	SUBPART(NPHY_FW, "NPHY Firmware", "NPHY"),
127 	SUBPART(TBT_FW, "TBT Firmware", "TBTP"),
128 	SUBPART(ICC, "ICC Firmware", "PCHC"),
129 };
130 
subpart_readable_name(enum bpdt_entry_type type)131 static const char *subpart_readable_name(enum bpdt_entry_type type)
132 {
133 	return subparts[type].readable_name;
134 }
135 
subpart_name(enum bpdt_entry_type type)136 static const char *subpart_name(enum bpdt_entry_type type)
137 {
138 	return subparts[type].name;
139 }
140 
subpart_alt_name(enum bpdt_entry_type type)141 static const char *subpart_alt_name(enum bpdt_entry_type type)
142 {
143 	return subparts[type].alt_name;
144 }
145 
subpart_buff(int type)146 static struct buffer *subpart_buff(int type)
147 {
148 	return &ifwi.subpart_buff[type];
149 }
150 
subpart_get_type_from_name(const char * name)151 static int subpart_get_type_from_name(const char *name)
152 {
153 	int i;
154 
155 	for (i = 0; i < MAX_SUBPARTS; i++) {
156 		if (subpart_name(i) == NULL)
157 			continue;
158 
159 		if (!strcmp(subpart_name(i), name))
160 			return i;
161 
162 		if (!strcmp(subpart_alt_name(i), name))
163 			return i;
164 	}
165 
166 	return -1;
167 }
168 
get_bpdt_ops(const struct buffer * buff)169 static const struct bpdt_ops *get_bpdt_ops(const struct buffer *buff)
170 {
171 	assert(buff || params.version_str);
172 
173 	for (size_t i = 0; i < ARRAY_SIZE(bpdt_ops_table); i++) {
174 		if (params.version_str) {
175 			if (!strcmp(params.version_str, bpdt_ops_table[i].version_str))
176 				return bpdt_ops_table[i].ops;
177 			else
178 				continue;
179 		}
180 		if (bpdt_ops_table[i].ops->match_version(buff))
181 			return bpdt_ops_table[i].ops;
182 	}
183 
184 	return NULL;
185 }
186 
get_subpart_hdr_ops(void)187 static const struct subpart_hdr_ops *get_subpart_hdr_ops(void)
188 {
189 	for (size_t i = 0; i < ARRAY_SIZE(subpart_hdr_ops_table); i++) {
190 		if (subpart_hdr_ops_table[i].version == ifwi.bpdt_ops->subpart_hdr_version)
191 			return subpart_hdr_ops_table[i].ops;
192 	}
193 
194 	return NULL;
195 }
196 
get_subpart_entry_ops(void)197 static const struct subpart_entry_ops *get_subpart_entry_ops(void)
198 {
199 	for (size_t i = 0; i < ARRAY_SIZE(subpart_entry_ops_table); i++) {
200 		if (subpart_entry_ops_table[i].version == ifwi.bpdt_ops->subpart_entry_version)
201 			return subpart_entry_ops_table[i].ops;
202 	}
203 
204 	return NULL;
205 }
206 
subpart_read(struct buffer * input_buff)207 static int subpart_read(struct buffer *input_buff)
208 {
209 	size_t input_size = buffer_size(input_buff);
210 	struct bpdt_entry *e = &ifwi.bpdt_entries[0];
211 	struct buffer *buff;
212 
213 	for (size_t i = 0; i < ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); i++, e++) {
214 		if (e->size == 0)
215 			continue;
216 
217 		if (e->type >= MAX_SUBPARTS) {
218 			ERROR("Invalid part type(%d)\n", e->type);
219 			return -1;
220 		}
221 
222 		if (e->offset + e->size > input_size) {
223 			ERROR("Part(%d) exceeds file size. Part offset=0x%x, Part size = 0x%x, File size = 0x%zx\n",
224 			      e->type, e->offset, e->size, input_size);
225 			return -1;
226 		}
227 
228 		buff = subpart_buff(e->type);
229 		if (buffer_size(buff) != 0) {
230 			ERROR("Multiple subparts of same type(%d %s)!\n",
231 			      e->type, subpart_name(e->type));
232 			return -1;
233 		}
234 
235 		buffer_splice(buff, input_buff, e->offset, e->size);
236 	}
237 
238 	return 0;
239 }
240 
find_bpdt_entry(uint32_t type)241 static struct bpdt_entry *find_bpdt_entry(uint32_t type)
242 {
243 	struct bpdt_entry *e = &ifwi.bpdt_entries[0];
244 
245 	for (size_t i = 0; i < ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); i++, e++) {
246 		if (e->type == type)
247 			return e;
248 	}
249 
250 	return NULL;
251 }
252 
new_bpdt_entry(void)253 static struct bpdt_entry *new_bpdt_entry(void)
254 {
255 	size_t count = ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr);
256 	if (count == MAX_SUBPARTS) {
257 		ERROR("No space for new BPDT entry!\n");
258 		return NULL;
259 	}
260 
261 	ifwi.bpdt_ops->inc_entry_count(ifwi.bpdt_hdr);
262 
263 	return &ifwi.bpdt_entries[count];
264 }
265 
set_file_end_offset(struct buffer * buff)266 static void set_file_end_offset(struct buffer *buff)
267 {
268 	struct bpdt_entry *e = &ifwi.bpdt_entries[0];
269 	size_t end_offset;
270 	size_t count = ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr);
271 
272 	ifwi.file_end_offset = ALIGN_UP(buffer_offset(buff), BUFF_SIZE_ALIGN);
273 
274 	for (size_t i = 0; i < count; i++, e++) {
275 		end_offset = e->offset + e->size;
276 		if (end_offset > ifwi.file_end_offset)
277 			ifwi.file_end_offset = end_offset;
278 
279 	}
280 }
281 
read_bpdt_entries(struct buffer * buff)282 static void read_bpdt_entries(struct buffer *buff)
283 {
284 	struct bpdt_entry *e = &ifwi.bpdt_entries[0];
285 	size_t count = ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr);
286 
287 	for (size_t i = 0; i < count; i++, e++) {
288 		READ_MEMBER(buff, e->type);
289 		READ_MEMBER(buff, e->offset);
290 		READ_MEMBER(buff, e->size);
291 	}
292 }
293 
write_bpdt_entries(struct buffer * buff)294 static int write_bpdt_entries(struct buffer *buff)
295 {
296 	struct bpdt_entry *e = &ifwi.bpdt_entries[0];
297 	size_t count = ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr);
298 
299 	if (buffer_size(buff) < count * sizeof(*e)) {
300 		ERROR("Not enough buffer space for bpdt entries!\n");
301 		return -1;
302 	}
303 
304 	for (size_t i = 0; i < count; i++, e++) {
305 		WRITE_MEMBER(buff, e->type);
306 		WRITE_MEMBER(buff, e->offset);
307 		WRITE_MEMBER(buff, e->size);
308 	}
309 
310 	return 0;
311 }
312 
print_bpdt_entries(void)313 static void print_bpdt_entries(void)
314 {
315 	const size_t count = ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr);
316 
317 	if (count == 0)
318 		return;
319 
320 	const struct bpdt_entry *e = &ifwi.bpdt_entries[0];
321 
322 	printf("\n * BPDT entries\n");
323 
324 	printf("%-25s%-25s%-25s%-25s%-25s%-25s\n", "Entry #",
325 	       "Partition Name", "Human readable name", "Type", "Offset", "Size");
326 
327 	printf("===================================================================="
328 	       "====================================================================\n");
329 
330 	for (size_t i = 0; i < count; i++) {
331 		printf("%-25zd%-25s%-25s%-25d0x%-23x0x%-23x"
332 		       "\n", i+1, subpart_name(e[i].type), subpart_readable_name(e[i].type),
333 		       e[i].type, e[i].offset, e[i].size);
334 	}
335 
336 	printf("===================================================================="
337 	       "====================================================================\n");
338 }
339 
ifwi_parse(const char * image_name)340 static int ifwi_parse(const char *image_name)
341 {
342 	struct buffer *input_buff = &ifwi.input_buff;
343 	struct buffer bpdt_buff;
344 
345 	if (buffer_from_file(input_buff, image_name)) {
346 		ERROR("Failed to read input file %s\n", image_name);
347 		return -1;
348 	}
349 
350 	buffer_clone(&bpdt_buff, input_buff);
351 
352 	ifwi.bpdt_ops = get_bpdt_ops(&bpdt_buff);
353 	if (!ifwi.bpdt_ops) {
354 		ERROR("No matching bpdt_ops!\n");
355 		return -1;
356 	}
357 
358 	ifwi.bpdt_hdr = ifwi.bpdt_ops->read_hdr(&bpdt_buff);
359 	if (ifwi.bpdt_hdr == NULL)
360 		return -1;
361 
362 	read_bpdt_entries(&bpdt_buff);
363 	set_file_end_offset(&bpdt_buff);
364 
365 	if (!ifwi.bpdt_ops->validate_checksum(ifwi.bpdt_hdr, &ifwi.bpdt_entries[0])) {
366 		ERROR("Checksum failed!\n");
367 		return -1;
368 	}
369 
370 	ifwi.subpart_hdr_ops = get_subpart_hdr_ops();
371 	if (ifwi.subpart_hdr_ops == NULL) {
372 		ERROR("No matching subpart_hdr_ops for given BPDT!\n");
373 		return -1;
374 	}
375 
376 	ifwi.subpart_entry_ops = get_subpart_entry_ops();
377 	if (ifwi.subpart_entry_ops == NULL) {
378 		ERROR("No matching subpart_entry_ops for given BPDT!\n");
379 		return -1;
380 	}
381 
382 	return subpart_read(&ifwi.input_buff);
383 }
384 
subpart_write(struct buffer * buff)385 static int subpart_write(struct buffer *buff)
386 {
387 	struct bpdt_entry *e;
388 	struct buffer *s_buff;
389 
390 	for (size_t i = 0; i < ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); i++) {
391 		e = &ifwi.bpdt_entries[i];
392 
393 		if (e->size == 0)
394 			continue;
395 
396 		if (e->offset + e->size > buffer_size(buff)) {
397 			ERROR("Subpart end(0x%x) overflows buffer size(0x%zx)\n",
398 			      e->offset + e->size, buffer_size(buff));
399 			return -1;
400 		}
401 
402 		s_buff = subpart_buff(e->type);
403 
404 		if (buffer_size(s_buff) != e->size) {
405 			ERROR("Subpart buffer size does not match BPDT entry size!\n");
406 			return -1;
407 		}
408 
409 		memcpy(buffer_get(buff) + e->offset, buffer_get(s_buff), e->size);
410 	}
411 
412 	return 0;
413 }
414 
ifwi_repack(void)415 static int ifwi_repack(void)
416 {
417 	if (!ifwi.repack)
418 		return 0;
419 
420 	struct buffer output_buff;
421 	const size_t size = ifwi.file_end_offset;
422 	struct buffer bpdt_buff;
423 
424 	if (buffer_create(&output_buff, size, "Output IFWI")) {
425 		ERROR("Unable to allocate output buff!\n");
426 		return -1;
427 	}
428 
429 	buffer_clone(&bpdt_buff, &output_buff);
430 
431 	ifwi.bpdt_ops->update_checksum(ifwi.bpdt_hdr, &ifwi.bpdt_entries[0]);
432 
433 	if (ifwi.bpdt_ops->write_hdr(&bpdt_buff, ifwi.bpdt_hdr))
434 		return -1;
435 
436 	if (write_bpdt_entries(&bpdt_buff))
437 		return -1;
438 
439 	subpart_write(&output_buff);
440 
441 	if (buffer_write_file(&output_buff, params.image_name)) {
442 		ERROR("File write error!\n");
443 		return -1;
444 	}
445 
446 	printf("Image written successfully to %s.\n", params.image_name);
447 	return 0;
448 }
449 
should_process_partition(int type)450 static bool should_process_partition(int type)
451 {
452 	if (params.partition_name) {
453 		const char *name = subpart_name(type);
454 
455 		if (!name)
456 			return false;
457 
458 		if (strcmp(params.partition_name, name))
459 			return false;
460 	} else if (params.partition_type != NO_PARTITION_TYPE) {
461 		if (params.partition_type != type)
462 			return false;
463 	}
464 
465 	return true;
466 }
467 
process_entries(int (* fn)(const struct bpdt_entry * e))468 static int process_entries(int (*fn)(const struct bpdt_entry *e))
469 {
470 	struct bpdt_entry *e = &ifwi.bpdt_entries[0];
471 	bool found = false;
472 
473 	for (size_t i = 0; i < ifwi.bpdt_ops->get_entry_count(ifwi.bpdt_hdr); i++, e++) {
474 		if (e->size == 0)
475 			continue;
476 
477 		if (!should_process_partition(e->type))
478 			continue;
479 
480 		if (fn(e))
481 			return -1;
482 
483 		found = true;
484 	}
485 
486 	if (!found && params.partition_name) {
487 		ERROR("Partition %s not found!\n", params.partition_name);
488 		return -1;
489 	}
490 
491 	if (!found && params.partition_type != NO_PARTITION_TYPE) {
492 		ERROR("Partition type %d not found!\n", params.partition_type);
493 		return -1;
494 	}
495 
496 	return 0;
497 }
498 
print_subpart(const struct bpdt_entry * e)499 static int print_subpart(const struct bpdt_entry *e)
500 {
501 	struct buffer buff;
502 	subpart_hdr_ptr hdr;
503 
504 	printf("\n\n * Subpart entry #%d(%s)\n", e->type, subpart_readable_name(e->type));
505 
506 	buffer_clone(&buff, subpart_buff(e->type));
507 	hdr = ifwi.subpart_hdr_ops->read(&buff);
508 	if (!hdr) {
509 		ERROR("Failed to read subpart header!\n");
510 		return -1;
511 	}
512 
513 	ifwi.subpart_hdr_ops->print(hdr);
514 	ifwi.subpart_entry_ops->print(&buff, ifwi.subpart_hdr_ops->get_entry_count(hdr));
515 	ifwi.subpart_hdr_ops->free(hdr);
516 
517 	return 0;
518 }
519 
cmd_print(void)520 static int cmd_print(void)
521 {
522 	ifwi.bpdt_ops->print_hdr(ifwi.bpdt_hdr);
523 	print_bpdt_entries();
524 
525 	if (!params.print_sub_parts && !params.partition_name &&
526 	    params.partition_type == NO_PARTITION_TYPE)
527 		return 0;
528 
529 	return process_entries(print_subpart);
530 }
531 
get_file_path(const char * name)532 static char *get_file_path(const char *name)
533 {
534 	size_t filename_len = strlen(name) + 1;
535 
536 	/* output_dir name followed by '/' */
537 	if (params.output_dir)
538 		filename_len += strlen(params.output_dir) + 1;
539 
540 	char *filepath = malloc(filename_len);
541 	if (!filepath)
542 		return NULL;
543 
544 	snprintf(filepath, filename_len, "%s%s%s",
545 		 params.output_dir ? : "",
546 		 params.output_dir ? "/" : "",
547 		 name);
548 
549 	return filepath;
550 }
551 
write_partition_to_file(const struct bpdt_entry * e)552 static int write_partition_to_file(const struct bpdt_entry *e)
553 {
554 	size_t end_offset = e->offset + e->size - 1;
555 
556 	if (end_offset > buffer_size(&ifwi.input_buff)) {
557 		ERROR("Offset out of bounds!\n");
558 		return -1;
559 	}
560 
561 	const char *name = subpart_name(e->type);
562 	char *filepath = get_file_path(name);
563 	if (!filepath) {
564 		ERROR("Failed to allocate filepath!\n");
565 		return -1;
566 	}
567 
568 	printf("Dumping %.4s in %s\n", name, filepath);
569 
570 	struct buffer buff;
571 	buffer_splice(&buff, &ifwi.input_buff, e->offset, e->size);
572 	buffer_write_file(&buff, filepath);
573 
574 	free(filepath);
575 	return 0;
576 }
577 
cmd_dump(void)578 static int cmd_dump(void)
579 {
580 	struct stat sb;
581 
582 	if (params.output_dir && (stat(params.output_dir, &sb) == -1)) {
583 		ERROR("Failed to stat %s: %s\n", params.output_dir, strerror(errno));
584 		return -1;
585 	}
586 
587 	return process_entries(write_partition_to_file);
588 }
589 
cmd_print_layout(void)590 static int cmd_print_layout(void)
591 {
592 	if (params.version_str == NULL) {
593 		ERROR("No version provided!\n");
594 		return -1;
595 	}
596 
597 	const struct bpdt_ops *ops = get_bpdt_ops(NULL);
598 	if (!ops) {
599 		ERROR("No matching bpdt_ops!\n");
600 		return -1;
601 	}
602 
603 	struct buffer buff;
604 	if (buffer_from_file(&buff, params.image_name)) {
605 		ERROR("Failed to read input file %s\n", params.image_name);
606 		return -1;
607 	}
608 
609 	ifwi.cse_layout = ops->read_layout(&buff);
610 	if (!ifwi.cse_layout) {
611 		ERROR("Failed to read CSE layout!\n");
612 		return -1;
613 	}
614 
615 	ops->print_layout(ifwi.cse_layout);
616 
617 	return 0;
618 }
619 
allocate_buffer(struct buffer * buff,struct buffer * wbuff,const char * str)620 static int allocate_buffer(struct buffer *buff, struct buffer *wbuff, const char *str)
621 {
622 	if (params.version_str == NULL) {
623 		ERROR("No version provided!\n");
624 		return -1;
625 	}
626 
627 	ifwi.bpdt_ops = get_bpdt_ops(NULL);
628 	if (!ifwi.bpdt_ops)
629 		return -1;
630 
631 	if (buffer_create(buff, BUFF_SIZE_ALIGN, str)) {
632 		ERROR("Buffer creation error!\n");
633 		return -1;
634 	}
635 
636 	void *data = buffer_get(buff);
637 	memset(data, 0xff, buffer_size(buff));
638 
639 	buffer_clone(wbuff, buff);
640 
641 	return 0;
642 }
643 
get_cse_region_end_offset(void)644 static size_t get_cse_region_end_offset(void)
645 {
646 	size_t offset = 0;
647 	size_t end_offset;
648 
649 	for (size_t i = 0; i < BP_TOTAL; i++) {
650 		end_offset = region_end(&params.layout_regions[i]);
651 		if (end_offset > offset)
652 			offset = end_offset;
653 	}
654 
655 	return offset;
656 }
657 
fill_layout_buffer(struct buffer * buff)658 static int fill_layout_buffer(struct buffer *buff)
659 {
660 	struct buffer wbuff;
661 
662 	if (allocate_buffer(buff, &wbuff, "CSE layout"))
663 		return -1;
664 
665 	ifwi.cse_layout = ifwi.bpdt_ops->create_layout(&params.layout_regions[0]);
666 	if (!ifwi.cse_layout) {
667 		ERROR("Failed to create layout!\n");
668 		return -1;
669 	}
670 
671 	if (ifwi.bpdt_ops->write_layout(&wbuff, ifwi.cse_layout)) {
672 		ERROR("Failed to write CSE layout!\n");
673 		return -1;
674 	}
675 
676 	return 0;
677 }
678 
cmd_create_layout(void)679 static int cmd_create_layout(void)
680 {
681 	struct buffer buff;
682 
683 	if (fill_layout_buffer(&buff))
684 		return -1;
685 
686 	buffer_write_file(&buff, params.image_name);
687 	return 0;
688 }
689 
cmd_create_cse_region(void)690 static int cmd_create_cse_region(void)
691 {
692 	size_t file_size = get_cse_region_end_offset();
693 	struct buffer cse_buff, layout_buff;
694 
695 	if (fill_layout_buffer(&layout_buff))
696 		return -1;
697 
698 	if (file_size == 0)
699 		file_size = buffer_size(&layout_buff);
700 
701 	file_size = ALIGN_UP(file_size, BUFF_SIZE_ALIGN);
702 	if (buffer_create(&cse_buff, file_size, "CSE buff")) {
703 		ERROR("CSE buffer creation error!\n");
704 		return -1;
705 	}
706 
707 	memset(buffer_get(&cse_buff), 0xff, buffer_size(&cse_buff));
708 	memcpy(buffer_get(&cse_buff), buffer_get(&layout_buff), buffer_size(&layout_buff));
709 
710 	for (size_t i = 0; i < BP_TOTAL; i++) {
711 		struct buffer wbuff, rbuff;
712 
713 		if (region_sz(&params.layout_regions[i]) == 0)
714 			continue;
715 
716 		buffer_clone(&wbuff, &cse_buff);
717 		buffer_seek(&wbuff, region_offset(&params.layout_regions[i]));
718 
719 		if (params.layout_files[i] == NULL) {
720 			if (i == 0) {
721 				ERROR("File name not provided for DP!\n");
722 			} else {
723 				ERROR("File name not provided for BP%zd!\n", i);
724 			}
725 			return -1;
726 		}
727 
728 		if (buffer_from_file(&rbuff, params.layout_files[i])) {
729 			ERROR("Failed to read %s\n", params.layout_files[i]);
730 			return -1;
731 		}
732 
733 		assert(buffer_size(&wbuff) >= buffer_size(&rbuff));
734 		memcpy(buffer_get(&wbuff), buffer_get(&rbuff), buffer_size(&rbuff));
735 	}
736 
737 	buffer_write_file(&cse_buff, params.image_name);
738 
739 	return 0;
740 }
741 
cmd_create_bpdt(void)742 static int cmd_create_bpdt(void)
743 {
744 	struct buffer buff;
745 	struct buffer wbuff;
746 
747 	if (allocate_buffer(&buff, &wbuff, "BPDT header"))
748 		return -1;
749 
750 	ifwi.bpdt_hdr = ifwi.bpdt_ops->create_hdr();
751 	if (!ifwi.bpdt_hdr) {
752 		ERROR("Failed to create BPDT header!\n");
753 		return -1;
754 	}
755 
756 	ifwi.bpdt_ops->update_checksum(ifwi.bpdt_hdr, NULL);
757 
758 	if (ifwi.bpdt_ops->write_hdr(&wbuff, ifwi.bpdt_hdr)) {
759 		ERROR("Failed to write BPDT header!\n");
760 		return -1;
761 	}
762 
763 	buffer_write_file(&buff, params.image_name);
764 	return 0;
765 }
766 
cmd_add(void)767 static int cmd_add(void)
768 {
769 	if (!params.partition_name && params.partition_type == NO_PARTITION_TYPE) {
770 		ERROR("Partition name/type is required for add!\n");
771 		return -1;
772 	}
773 
774 	int type;
775 
776 	if (params.partition_name) {
777 		type = subpart_get_type_from_name(params.partition_name);
778 		if (type == NO_PARTITION_TYPE) {
779 			ERROR("Invalid partition %s\n", params.partition_name);
780 			return -1;
781 		}
782 	} else {
783 		type = params.partition_type;
784 		if (type > MAX_SUBPARTS) {
785 			ERROR("Invalid type %d\n", type);
786 			return -1;
787 		}
788 	}
789 
790 	struct bpdt_entry *e = find_bpdt_entry(type);
791 	if (e) {
792 		ERROR("Partition %s(%d) already exists!\n", params.partition_name ? : "", type);
793 		return -1;
794 	}
795 
796 	e = new_bpdt_entry();
797 	if (e == NULL)
798 		return -1;
799 
800 	e->type = type;
801 	e->offset = 0;
802 	e->size = 0;
803 
804 	ifwi.repack = true;
805 
806 	if (params.input_file == NULL)
807 		return 0;
808 
809 	struct buffer *buff = subpart_buff(type);
810 	if (buffer_from_file_aligned_size(buff, params.input_file, BUFF_SIZE_ALIGN)) {
811 		ERROR("Failed to read input file %s\n", params.input_file);
812 		return -1;
813 	}
814 
815 	e->offset = ALIGN_UP(ifwi.file_end_offset, BUFF_SIZE_ALIGN);
816 	e->size = buffer_size(buff);
817 
818 	ifwi.file_end_offset = e->offset + e->size;
819 
820 	return 0;
821 }
822 
parse_region(struct region * r,char * arg)823 static void parse_region(struct region *r, char *arg)
824 {
825 	char *tok;
826 
827 	tok = strtok(arg, ":");
828 	r->offset = strtol(tok, NULL, 0);
829 
830 	tok = strtok(NULL, ":");
831 	r->size = strtol(tok, NULL, 0);
832 }
833 
834 static struct command {
835 	const char *name;
836 	const char *optstring;
837 	int (*cb)(void);
838 	bool parse_ifwi;
839 } commands[] = {
840 	{ "print", "n:st:?", cmd_print, true },
841 	{ "dump", "n:o:t:?", cmd_dump, true },
842 	{ "create-layout", "v:?", cmd_create_layout, false },
843 	{ "print-layout", "v:?", cmd_print_layout, false },
844 	{ "create-bpdt", "v:?", cmd_create_bpdt, false },
845 	{ "add", "f:n:t:v:?", cmd_add, true },
846 	{ "create-cse-region", "v:?", cmd_create_cse_region, false },
847 };
848 
849 enum {
850 	LONGOPT_START = 256,
851 	LONGOPT_BP1 = LONGOPT_START,
852 	LONGOPT_BP2,
853 	LONGOPT_BP3,
854 	LONGOPT_BP4,
855 	LONGOPT_DATA,
856 	LONGOPT_BP1_FILE,
857 	LONGOPT_BP2_FILE,
858 	LONGOPT_BP3_FILE,
859 	LONGOPT_BP4_FILE,
860 	LONGOPT_DATA_FILE,
861 
862 	LONGOPT_END,
863 };
864 
865 static struct option long_options[] = {
866 	{"help",	    required_argument, 0, 'h'},
867 	{"parition_name",   required_argument, 0, 'n'},
868 	{"output_dir",      required_argument, 0, 'o'},
869 	{"sub_partition",   no_argument,       0, 's'},
870 	{"version",         required_argument, 0, 'v'},
871 	{"bp1",             required_argument, 0, LONGOPT_BP1},
872 	{"bp1_file",        required_argument, 0, LONGOPT_BP1_FILE},
873 	{"bp2",             required_argument, 0, LONGOPT_BP2},
874 	{"bp2_file",        required_argument, 0, LONGOPT_BP2_FILE},
875 	{"bp3",             required_argument, 0, LONGOPT_BP3},
876 	{"bp3_file",        required_argument, 0, LONGOPT_BP3_FILE},
877 	{"bp4",             required_argument, 0, LONGOPT_BP4},
878 	{"bp4_file",        required_argument, 0, LONGOPT_BP4_FILE},
879 	{"dp",              required_argument, 0, LONGOPT_DATA},
880 	{"dp_file",         required_argument, 0, LONGOPT_DATA_FILE},
881 	{NULL,		    0,                 0,  0 }
882 };
883 
valid_opt(size_t i,int c)884 static bool valid_opt(size_t i, int c)
885 {
886 	/* Check if it is one of the optstrings supported by the command. */
887 	if (strchr(commands[i].optstring, c))
888 		return true;
889 
890 	/*
891 	 * Check if it is one of the non-ASCII characters. Currently, the
892 	 * non-ASCII characters are only checked against the valid list
893 	 * irrespective of the command.
894 	 */
895 	return c >= LONGOPT_START && c < LONGOPT_END;
896 }
897 
usage(const char * name)898 static void usage(const char *name)
899 {
900 	printf("%s: Utility for stitching CSE components\n"
901 	       "USAGE:\n"
902 	       " %s FILE COMMAND\n\n"
903 	       "COMMANDs:\n"
904 	       " print [-s][-n NAME][-t TYPE]\n"
905 	       " dump [-o DIR][-n NAME]\n"
906 	       " create-layout --dp <offset:size> --bp* <offset:size> -v VERSION\n"
907 	       " create-cse-region --dp <offset:size> --dp_file <FILE> --bp* <offset:size>"
908 	       " --bp*_file <FILE> -v VERSION\n"
909 	       " print-layout -v VERSION\n"
910 	       " create-bpdt -v VERSION\n"
911 	       " add [-n NAME][-t TYPE][-f INPUT_FILE]\n"
912 	       "\nOPTIONS:\n"
913 	       " -f INPUT_FILE       : Input file\n"
914 	       " -n NAME             : Sub-partition name\n"
915 	       " -o DIR              : Output directory\n"
916 	       " -s                  : Print sub-partition info\n"
917 	       " -t TYPE             : Sub-partition type\n"
918 	       " -v VERSION          : BPDT version\n"
919 	       " --dp <offset:size>  : Offset and size of data partition\n"
920 	       " --dp_file <FILE>    : File for data partition\n"
921 	       " --bp1 <offset:size> : Offset and size of BP1\n"
922 	       " --bp1_file <FILE>   : File for BP1 partition\n"
923 	       " --bp2 <offset:size> : Offset and size of BP2\n"
924 	       " --bp2_file <FILE>   : File for BP2 partition\n"
925 	       " --bp3 <offset:size> : Offset and size of BP3\n"
926 	       " --bp3_file <FILE>   : File for BP3 partition\n"
927 	       " --bp4 <offset:size> : Offset and size of BP4\n"
928 	       " --bp4_file <FILE>   : File for BP4 partition\n"
929 	       "\n",
930 	       name, name);
931 }
932 
main(int argc,char ** argv)933 int main(int argc, char **argv)
934 {
935 	if (argc < 3) {
936 		printf("Incorrect number of args(%d)!\n", argc);
937 		usage(argv[0]);
938 		return 1;
939 	}
940 
941 	const char *prog_name = argv[0];
942 	const char *image_name = argv[1];
943 	const char *cmd = argv[2];
944 
945 	size_t i;
946 
947 	params.partition_type = NO_PARTITION_TYPE;
948 	params.image_name = image_name;
949 
950 	for (i = 0; i < ARRAY_SIZE(commands); i++) {
951 		if (strcmp(cmd, commands[i].name))
952 			continue;
953 
954 		int c;
955 		int option_index;
956 
957 		while (1) {
958 			c = getopt_long(argc, argv, commands[i].optstring,
959 					long_options, &option_index);
960 
961 			if (c == -1)
962 				break;
963 
964 			if (!valid_opt(i, c)) {
965 				if (c < LONGOPT_START) {
966 					ERROR("Invalid option -- '%c'\n", c);
967 				} else {
968 					ERROR("Invalid option -- '%d'\n", c);
969 				}
970 				usage(prog_name);
971 				return 1;
972 			}
973 
974 			switch (c) {
975 			case 'f':
976 				params.input_file = optarg;
977 				break;
978 			case 'n':
979 				params.partition_name = optarg;
980 				break;
981 			case 'o':
982 				params.output_dir = optarg;
983 				break;
984 			case 's':
985 				params.print_sub_parts = true;
986 				break;
987 			case 'v':
988 				params.version_str = optarg;
989 				break;
990 			case 't':
991 				params.partition_type = atoi(optarg);
992 				break;
993 			case LONGOPT_BP1:
994 				parse_region(&params.layout_regions[BP1], optarg);
995 				break;
996 			case LONGOPT_BP2:
997 				parse_region(&params.layout_regions[BP2], optarg);
998 				break;
999 			case LONGOPT_BP3:
1000 				parse_region(&params.layout_regions[BP3], optarg);
1001 				break;
1002 			case LONGOPT_BP4:
1003 				parse_region(&params.layout_regions[BP4], optarg);
1004 				break;
1005 			case LONGOPT_DATA:
1006 				parse_region(&params.layout_regions[DP], optarg);
1007 				break;
1008 			case LONGOPT_BP1_FILE:
1009 				params.layout_files[BP1] = optarg;
1010 				break;
1011 			case LONGOPT_BP2_FILE:
1012 				params.layout_files[BP2] = optarg;
1013 				break;
1014 			case LONGOPT_BP3_FILE:
1015 				params.layout_files[BP3] = optarg;
1016 				break;
1017 			case LONGOPT_BP4_FILE:
1018 				params.layout_files[BP4] = optarg;
1019 				break;
1020 			case LONGOPT_DATA_FILE:
1021 				params.layout_files[DP] = optarg;
1022 				break;
1023 			case 'h':
1024 			case '?':
1025 			default:
1026 				usage(prog_name);
1027 				return 1;
1028 			}
1029 		}
1030 
1031 		break;
1032 	}
1033 
1034 	if (i == ARRAY_SIZE(commands)) {
1035 		printf("No command match %s!\n", cmd);
1036 		usage(prog_name);
1037 		return 1;
1038 	}
1039 
1040 	if (commands[i].parse_ifwi && ifwi_parse(image_name))
1041 		return 1;
1042 
1043 	if (commands[i].cb())
1044 		return 1;
1045 
1046 	return ifwi_repack();
1047 }
1048