blob: f53b3904af5588a9219569829a8f94d73e4909b1 [file] [log] [blame]
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -07001/* 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
16static 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;
Furquan Shaikh8b4ca152021-10-09 23:06:09 -070024 struct region layout_regions[BP_TOTAL];
Furquan Shaikhbf848ad2021-10-10 23:07:09 -070025 const char *layout_files[BP_TOTAL];
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -070026} params;
27
28static 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
36static 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
44static 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
51enum 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
80static 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
100static 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
131static const char *subpart_readable_name(enum bpdt_entry_type type)
132{
133 return subparts[type].readable_name;
134}
135
136static const char *subpart_name(enum bpdt_entry_type type)
137{
138 return subparts[type].name;
139}
140
141static const char *subpart_alt_name(enum bpdt_entry_type type)
142{
143 return subparts[type].alt_name;
144}
145
146static struct buffer *subpart_buff(int type)
147{
148 return &ifwi.subpart_buff[type];
149}
150
151static 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
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700169static 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
187static 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
197static 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
207static 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
241static 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
253static 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
266static 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
282static 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
294static 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
313static 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
340static 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
385static 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
415static 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
450static 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
468static 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
499static 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
520static 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
532static 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
552static 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
578static 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
590static 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
620static 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
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700644static 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
Furquan Shaikh8b4ca152021-10-09 23:06:09 -0700658static int fill_layout_buffer(struct buffer *buff)
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700659{
Furquan Shaikh8b4ca152021-10-09 23:06:09 -0700660 struct buffer wbuff;
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700661
Furquan Shaikh8b4ca152021-10-09 23:06:09 -0700662 if (allocate_buffer(buff, &wbuff, "CSE layout"))
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700663 return -1;
664
Furquan Shaikh8b4ca152021-10-09 23:06:09 -0700665 ifwi.cse_layout = ifwi.bpdt_ops->create_layout(&params.layout_regions[0]);
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700666 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
Furquan Shaikh8b4ca152021-10-09 23:06:09 -0700676 return 0;
677}
678
679static int cmd_create_layout(void)
680{
681 struct buffer buff;
682
683 if (fill_layout_buffer(&buff))
684 return -1;
685
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700686 buffer_write_file(&buff, params.image_name);
687 return 0;
688}
689
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700690static 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
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700742static 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
767static 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
823static 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
834static 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 },
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700846 { "create-cse-region", "v:?", cmd_create_cse_region, false },
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700847};
848
849enum {
850 LONGOPT_START = 256,
851 LONGOPT_BP1 = LONGOPT_START,
852 LONGOPT_BP2,
853 LONGOPT_BP3,
854 LONGOPT_BP4,
855 LONGOPT_DATA,
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700856 LONGOPT_BP1_FILE,
857 LONGOPT_BP2_FILE,
858 LONGOPT_BP3_FILE,
859 LONGOPT_BP4_FILE,
860 LONGOPT_DATA_FILE,
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700861
862 LONGOPT_END,
863};
864
865static 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},
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700872 {"bp1_file", required_argument, 0, LONGOPT_BP1_FILE},
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700873 {"bp2", required_argument, 0, LONGOPT_BP2},
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700874 {"bp2_file", required_argument, 0, LONGOPT_BP2_FILE},
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700875 {"bp3", required_argument, 0, LONGOPT_BP3},
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700876 {"bp3_file", required_argument, 0, LONGOPT_BP3_FILE},
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700877 {"bp4", required_argument, 0, LONGOPT_BP4},
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700878 {"bp4_file", required_argument, 0, LONGOPT_BP4_FILE},
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700879 {"dp", required_argument, 0, LONGOPT_DATA},
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700880 {"dp_file", required_argument, 0, LONGOPT_DATA_FILE},
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700881 {NULL, 0, 0, 0 }
882};
883
884static 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
898static 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"
Furquan Shaikh8b4ca152021-10-09 23:06:09 -0700906 " create-layout --dp <offset:size> --bp* <offset:size> -v VERSION\n"
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700907 " create-cse-region --dp <offset:size> --dp_file <FILE> --bp* <offset:size>"
908 " --bp*_file <FILE> -v VERSION\n"
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700909 " 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"
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700920 " --dp_file <FILE> : File for data partition\n"
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700921 " --bp1 <offset:size> : Offset and size of BP1\n"
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700922 " --bp1_file <FILE> : File for BP1 partition\n"
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700923 " --bp2 <offset:size> : Offset and size of BP2\n"
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700924 " --bp2_file <FILE> : File for BP2 partition\n"
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700925 " --bp3 <offset:size> : Offset and size of BP3\n"
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700926 " --bp3_file <FILE> : File for BP3 partition\n"
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700927 " --bp4 <offset:size> : Offset and size of BP4\n"
Furquan Shaikhbf848ad2021-10-10 23:07:09 -0700928 " --bp4_file <FILE> : File for BP4 partition\n"
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700929 "\n",
930 name, name);
931}
932
933int 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:
Furquan Shaikh8b4ca152021-10-09 23:06:09 -0700994 parse_region(&params.layout_regions[BP1], optarg);
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700995 break;
996 case LONGOPT_BP2:
Furquan Shaikh8b4ca152021-10-09 23:06:09 -0700997 parse_region(&params.layout_regions[BP2], optarg);
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -0700998 break;
999 case LONGOPT_BP3:
Furquan Shaikh8b4ca152021-10-09 23:06:09 -07001000 parse_region(&params.layout_regions[BP3], optarg);
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -07001001 break;
1002 case LONGOPT_BP4:
Furquan Shaikh8b4ca152021-10-09 23:06:09 -07001003 parse_region(&params.layout_regions[BP4], optarg);
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -07001004 break;
1005 case LONGOPT_DATA:
Furquan Shaikh8b4ca152021-10-09 23:06:09 -07001006 parse_region(&params.layout_regions[DP], optarg);
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -07001007 break;
Furquan Shaikhbf848ad2021-10-10 23:07:09 -07001008 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;
Furquan Shaikhd7fb6a92021-09-16 22:04:11 -07001023 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}