blob: 8c47107c7b9456aab5a369520a9aa6534215f883 [file] [log] [blame]
Alexander Graf5329d672018-04-13 14:18:52 +02001/*
2 * Copyright (C) 2018 Alexander Graf <agraf@suse.de>
3 *
4 * SPDX-License-Identifier: GPL-2.0+
5 */
6
7#include "imagetool.h"
8#include "mkimage.h"
9#include "zynqmpimage.h"
10#include <elf.h>
11#include <image.h>
12
13struct bif_entry {
14 const char *filename;
15 uint64_t flags;
16 uint64_t dest_cpu;
17 uint64_t exp_lvl;
18 uint64_t dest_dev;
19 uint64_t load;
20 uint64_t entry;
21 size_t offset;
22};
23
24enum bif_flag {
25 BIF_FLAG_AESKEYFILE,
26 BIF_FLAG_INIT,
27 BIF_FLAG_UDF_BH,
28 BIF_FLAG_HEADERSIGNATURE,
29 BIF_FLAG_PPKFILE,
30 BIF_FLAG_PSKFILE,
31 BIF_FLAG_SPKFILE,
32 BIF_FLAG_SSKFILE,
33 BIF_FLAG_SPKSIGNATURE,
34 BIF_FLAG_FSBL_CONFIG,
35 BIF_FLAG_AUTH_PARAMS,
36 BIF_FLAG_KEYSRC_ENCRYPTION,
37 BIF_FLAG_PMUFW_IMAGE,
38 BIF_FLAG_BOOTLOADER,
39 BIF_FLAG_TZ,
40 BIF_FLAG_BH_KEY_IV,
41 BIF_FLAG_BH_KEYFILE,
42 BIF_FLAG_PUF_FILE,
43 BIF_FLAG_AARCH32,
44 BIF_FLAG_PART_OWNER_UBOOT,
45
46 /* Internal flags */
47 BIF_FLAG_BIT_FILE,
48 BIF_FLAG_ELF_FILE,
49 BIF_FLAG_BIN_FILE,
50};
51
52struct bif_flags {
53 const char name[32];
54 uint64_t flag;
55 char *(*parse)(char *line, struct bif_entry *bf);
56};
57
58struct bif_file_type {
59 const char name[32];
60 uint32_t header;
61 int (*add)(struct bif_entry *bf);
62};
63
64struct bif_output {
65 size_t data_len;
66 char *data;
67 struct image_header_table *imgheader;
68 struct zynqmp_header *header;
69 struct partition_header *last_part;
70};
71
72struct bif_output bif_output;
73
74static uint32_t zynqmp_csum(void *start, void *end)
75{
76 uint32_t checksum = 0;
77 uint32_t *ptr32 = start;
78
79 while (ptr32 != end) {
80 checksum += le32_to_cpu(*ptr32);
81 ptr32++;
82 }
83
84 return ~checksum;
85}
86
87static int zynqmpbif_check_params(struct image_tool_params *params)
88{
89 if (!params)
90 return 0;
91
92 if (params->addr != 0x0) {
93 fprintf(stderr, "Error: Load Address can not be specified.\n");
94 return -1;
95 }
96
97 if (params->eflag) {
98 fprintf(stderr, "Error: Entry Point can not be specified.\n");
99 return -1;
100 }
101
102 return !(params->lflag || params->dflag);
103}
104
105static int zynqmpbif_check_image_types(uint8_t type)
106{
107 return (type == IH_TYPE_ZYNQMPBIF) ? EXIT_SUCCESS : EXIT_FAILURE;
108}
109
110static char *parse_dest_cpu(char *line, struct bif_entry *bf)
111{
112 uint64_t i;
113
114 for (i = 0; i < ARRAY_SIZE(dest_cpus); i++) {
115 if (!strncmp(line, dest_cpus[i], strlen(dest_cpus[i]))) {
116 bf->dest_cpu = i << PART_ATTR_DEST_CPU_SHIFT;
117 return line + strlen(dest_cpus[i]);
118 }
119
120 /* a5x can also be written as a53 */
121 if (!strncmp(dest_cpus[i], "a5x", 3)) {
122 char a53[] = "a53-X";
123
124 a53[4] = dest_cpus[i][4];
125 if (!strncmp(line, a53, strlen(a53))) {
126 bf->dest_cpu = i << PART_ATTR_DEST_CPU_SHIFT;
127 return line + strlen(a53);
128 }
129 }
130 }
131
132 return line;
133}
134
135static char *parse_el(char *line, struct bif_entry *bf)
136{
137 const char *dest_els[] = { "none", "el-0", "el-1", "el-2", "el-3" };
138 int i;
139
140 for (i = 0; i < ARRAY_SIZE(dest_els); i++) {
141 if (!strncmp(line, dest_els[i], strlen(dest_els[i]))) {
142 bf->exp_lvl = i;
143 return line + strlen(dest_els[i]);
144 }
145 }
146
147 return line;
148}
149
150static char *parse_load(char *line, struct bif_entry *bf)
151{
152 char *endptr;
153
154 bf->load = strtoll(line, &endptr, 0);
155
156 return endptr;
157}
158
159static char *parse_entry(char *line, struct bif_entry *bf)
160{
161 char *endptr;
162
163 bf->entry = strtoll(line, &endptr, 0);
164
165 return endptr;
166}
167
168static char *parse_offset(char *line, struct bif_entry *bf)
169{
170 char *endptr;
171
172 bf->offset = strtoll(line, &endptr, 0);
173
174 return endptr;
175}
176
177static char *parse_partition_owner(char *line, struct bif_entry *bf)
178{
179 char *endptr = NULL;
180
181 if (!strncmp(line, "fsbl", 4)) {
182 endptr = line + 4;
183 } else if (!strncmp(line, "uboot", 5)) {
184 bf->flags |= 1ULL << BIF_FLAG_PART_OWNER_UBOOT;
185 endptr = line + 5;
186 } else {
187 printf("ERROR: Unknown partition type '%s'\n", line);
188 }
189
190 return endptr;
191}
192
193static const struct bif_flags bif_flags[] = {
194 { "fsbl_config", BIF_FLAG_FSBL_CONFIG },
195 { "trustzone", BIF_FLAG_TZ },
196 { "pmufw_image", BIF_FLAG_PMUFW_IMAGE },
197 { "bootloader", BIF_FLAG_BOOTLOADER },
198 { "destination_cpu=", 0, parse_dest_cpu },
199 { "exception_level=", 0, parse_el },
200 { "load=", 0, parse_load },
201 { "startup=", 0, parse_entry },
202 { "offset=", 0, parse_offset },
203 { "partition_owner=", 0, parse_partition_owner },
204};
205
206static char *read_full_file(const char *filename, size_t *size)
207{
208 char *buf, *bufp;
209 struct stat sbuf;
210 int len = 0, r, fd;
211
212 fd = open(filename, O_RDONLY);
213 if (fd < 0)
214 return NULL;
215
216 if (fstat(fd, &sbuf) < 0)
217 return NULL;
218
219 if (size)
220 *size = sbuf.st_size;
221
222 buf = malloc(sbuf.st_size);
223 if (!buf)
224 return NULL;
225
226 bufp = buf;
227 while (len < sbuf.st_size) {
228 r = read(fd, bufp, sbuf.st_size - len);
229 if (r < 0)
230 return NULL;
231 len += r;
232 bufp += r;
233 }
234
235 close(fd);
236
237 return buf;
238}
239
240static int bif_add_blob(const void *data, size_t len, size_t *offset)
241{
242 size_t new_size;
243 uintptr_t header_off;
244 uintptr_t last_part_off;
245 uintptr_t imgheader_off;
246 uintptr_t old_data = (uintptr_t)bif_output.data;
247 void *new_data;
248
249 header_off = (uintptr_t)bif_output.header - old_data;
250 last_part_off = (uintptr_t)bif_output.last_part - old_data;
251 imgheader_off = (uintptr_t)bif_output.imgheader - old_data;
252
253 if (offset && *offset) {
254 /* Pad to a given offset */
255 if (bif_output.data_len > *offset) {
256 printf("Can not pad to offset %zx\n", *offset);
257 return -1;
258 }
259
260 bif_output.data_len = *offset;
261 }
262
263 new_size = ROUND(bif_output.data_len + len, 64);
264 new_data = realloc(bif_output.data, new_size);
265 memcpy(new_data + bif_output.data_len, data, len);
266 if (offset)
267 *offset = bif_output.data_len;
268 bif_output.data = new_data;
269 bif_output.data_len = new_size;
270
271 /* Readjust internal pointers */
272 if (bif_output.header)
273 bif_output.header = new_data + header_off;
274 if (bif_output.last_part)
275 bif_output.last_part = new_data + last_part_off;
276 if (bif_output.imgheader)
277 bif_output.imgheader = new_data + imgheader_off;
278
279 return 0;
280}
281
282static int bif_init(void)
283{
284 struct zynqmp_header header = { { 0 } };
285 int r;
286
287 zynqmpimage_default_header(&header);
288
289 r = bif_add_blob(&header, sizeof(header), NULL);
290 if (r)
291 return r;
292
293 bif_output.header = (void *)bif_output.data;
294
295 return 0;
296}
297
298static int bif_add_pmufw(struct bif_entry *bf, const char *data, size_t len)
299{
300 int r;
301
302 if (bif_output.header->image_offset) {
303 printf("PMUFW expected before bootloader in your .bif file!\n");
304 return -1;
305 }
306
307 r = bif_add_blob(data, len, &bf->offset);
308 if (r)
309 return r;
310
311 len = ROUND(len, 64);
312 bif_output.header->pfw_image_length = cpu_to_le32(len);
313 bif_output.header->total_pfw_image_length = cpu_to_le32(len);
314 bif_output.header->image_offset = cpu_to_le32(bf->offset);
315
316 return 0;
317}
318
319static int bif_add_part(struct bif_entry *bf, const char *data, size_t len)
320{
321 size_t parthdr_offset = 0;
Michael Tretter5a319e82018-12-03 16:37:53 +0100322 size_t len_padded = ROUND(len, 4);
323
Alexander Graf5329d672018-04-13 14:18:52 +0200324 struct partition_header parthdr = {
Michael Tretter5a319e82018-12-03 16:37:53 +0100325 .len_enc = cpu_to_le32(len_padded / 4),
326 .len_unenc = cpu_to_le32(len_padded / 4),
327 .len = cpu_to_le32(len_padded / 4),
Alexander Graf5329d672018-04-13 14:18:52 +0200328 .entry_point = cpu_to_le64(bf->entry),
329 .load_address = cpu_to_le64(bf->load),
330 };
331 int r;
332 uint32_t csum;
333
Michael Tretter5a319e82018-12-03 16:37:53 +0100334 if (len < len_padded) {
335 char *newdata = malloc(len_padded);
336 memcpy(newdata, data, len);
337 memset(newdata + len, 0, len_padded - len);
338 data = newdata;
339 }
340
Alexander Graf5329d672018-04-13 14:18:52 +0200341 if (bf->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE))
342 return bif_add_pmufw(bf, data, len);
343
344 r = bif_add_blob(data, len, &bf->offset);
345 if (r)
346 return r;
347
348 parthdr.offset = cpu_to_le32(bf->offset / 4);
349
350 if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) {
351 if (bif_output.last_part) {
352 printf("ERROR: Bootloader expected before others\n");
353 return -1;
354 }
355
356 parthdr.offset = cpu_to_le32(bif_output.header->image_offset);
357 parthdr.len = cpu_to_le32((bf->offset + len -
358 bif_output.header->image_offset) / 4);
359 parthdr.len_enc = parthdr.len;
360 parthdr.len_unenc = parthdr.len;
361 }
362
363 /* Normalize EL */
364 bf->exp_lvl = bf->exp_lvl ? bf->exp_lvl - 1 : 3;
365 parthdr.attributes |= bf->exp_lvl << PART_ATTR_TARGET_EL_SHIFT;
366 parthdr.attributes |= bf->dest_dev;
367 parthdr.attributes |= bf->dest_cpu;
368 if (bf->flags & (1ULL << BIF_FLAG_TZ))
369 parthdr.attributes |= PART_ATTR_TZ_SECURE;
370 if (bf->flags & (1ULL << BIF_FLAG_PART_OWNER_UBOOT))
371 parthdr.attributes |= PART_ATTR_PART_OWNER_UBOOT;
372 switch (bf->dest_cpu) {
373 case PART_ATTR_DEST_CPU_NONE:
374 case PART_ATTR_DEST_CPU_A53_0:
375 case PART_ATTR_DEST_CPU_A53_1:
376 case PART_ATTR_DEST_CPU_A53_2:
377 case PART_ATTR_DEST_CPU_A53_3:
378 if (bf->flags & (1ULL << BIF_FLAG_AARCH32))
379 parthdr.attributes |= PART_ATTR_A53_EXEC_AARCH32;
380 }
381
382 csum = zynqmp_csum(&parthdr, &parthdr.checksum);
383 parthdr.checksum = cpu_to_le32(csum);
384
385 r = bif_add_blob(&parthdr, sizeof(parthdr), &parthdr_offset);
386 if (r)
387 return r;
388
389 /* Add image header table if not there yet */
390 if (!bif_output.imgheader) {
391 size_t imghdr_off = 0;
392 struct image_header_table imghdr = {
393 .version = cpu_to_le32(0x01020000),
394 .nr_parts = 0,
395 };
396
397 r = bif_add_blob(&imghdr, sizeof(imghdr), &imghdr_off);
398 if (r)
399 return r;
400
401 bif_output.header->image_header_table_offset = imghdr_off;
402 bif_output.imgheader = (void *)(bif_output.data + imghdr_off);
403 }
404
405 bif_output.imgheader->nr_parts = cpu_to_le32(le32_to_cpu(
406 bif_output.imgheader->nr_parts) + 1);
407
408 /* Link to this partition header */
409 if (bif_output.last_part) {
410 bif_output.last_part->next_partition_offset =
411 cpu_to_le32(parthdr_offset / 4);
412
413 /* Recalc checksum of last_part */
414 csum = zynqmp_csum(bif_output.last_part,
415 &bif_output.last_part->checksum);
416 bif_output.last_part->checksum = cpu_to_le32(csum);
417 } else {
418 bif_output.imgheader->partition_header_offset =
419 cpu_to_le32(parthdr_offset / 4);
420 }
421 bif_output.last_part = (void *)(bif_output.data + parthdr_offset);
422
423 if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) {
424 bif_output.header->image_load = cpu_to_le32(bf->load);
425 if (!bif_output.header->image_offset)
426 bif_output.header->image_offset =
427 cpu_to_le32(bf->offset);
Michal Simeka797b9b2018-12-14 10:53:54 +0100428 bif_output.header->image_size = cpu_to_le32(len_padded);
429 bif_output.header->image_stored_size = cpu_to_le32(len_padded);
Alexander Graf5329d672018-04-13 14:18:52 +0200430
431 bif_output.header->image_attributes &= ~HEADER_CPU_SELECT_MASK;
432 switch (bf->dest_cpu) {
433 default:
434 case PART_ATTR_DEST_CPU_A53_0:
435 if (bf->flags & BIF_FLAG_AARCH32)
436 bif_output.header->image_attributes |=
437 HEADER_CPU_SELECT_A53_32BIT;
438 else
439 bif_output.header->image_attributes |=
440 HEADER_CPU_SELECT_A53_64BIT;
441 break;
442 case PART_ATTR_DEST_CPU_R5_0:
443 bif_output.header->image_attributes |=
444 HEADER_CPU_SELECT_R5_SINGLE;
445 break;
446 case PART_ATTR_DEST_CPU_R5_L:
447 bif_output.header->image_attributes |=
448 HEADER_CPU_SELECT_R5_DUAL;
449 break;
450 }
451 }
452
453 return 0;
454}
455
456/* Add .bit bitstream */
457static int bif_add_bit(struct bif_entry *bf)
458{
459 char *bit = read_full_file(bf->filename, NULL);
460 char *bitbin;
461 uint8_t initial_header[] = { 0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f,
462 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01, 0x61 };
463 uint16_t len;
464 uint32_t bitlen;
465 int i;
466
467 if (!bit)
468 return -1;
469
470 /* Skip initial header */
471 if (memcmp(bit, initial_header, sizeof(initial_header)))
472 return -1;
473
474 bit += sizeof(initial_header);
475
476 /* Design name */
477 len = be16_to_cpu(*(uint16_t *)bit);
478 bit += sizeof(uint16_t);
479 debug("Design: %s\n", bit);
480 bit += len;
481
482 /* Device identifier */
483 if (*bit != 'b')
484 return -1;
485 bit++;
486 len = be16_to_cpu(*(uint16_t *)bit);
487 bit += sizeof(uint16_t);
488 debug("Device: %s\n", bit);
489 bit += len;
490
491 /* Date */
492 if (*bit != 'c')
493 return -1;
494 bit++;
495 len = be16_to_cpu(*(uint16_t *)bit);
496 bit += sizeof(uint16_t);
497 debug("Date: %s\n", bit);
498 bit += len;
499
500 /* Time */
501 if (*bit != 'd')
502 return -1;
503 bit++;
504 len = be16_to_cpu(*(uint16_t *)bit);
505 bit += sizeof(uint16_t);
506 debug("Time: %s\n", bit);
507 bit += len;
508
509 /* Bitstream length */
510 if (*bit != 'e')
511 return -1;
512 bit++;
513 bitlen = be32_to_cpu(*(uint32_t *)bit);
514 bit += sizeof(uint32_t);
515 bitbin = bit;
516
517 debug("Bitstream Length: 0x%x\n", bitlen);
518 for (i = 0; i < bitlen; i += sizeof(uint32_t)) {
519 uint32_t *bitbin32 = (uint32_t *)&bitbin[i];
520 *bitbin32 = __swab32(*bitbin32);
521 }
522
523 if (!bf->dest_dev)
524 bf->dest_dev = PART_ATTR_DEST_DEVICE_PL;
525
526 bf->load = 0xffffffff;
527 bf->entry = 0;
528
529 bf->flags |= 1ULL << BIF_FLAG_BIT_FILE;
530 return bif_add_part(bf, bit, bitlen);
531}
532
533/* Add .bin bitstream */
534static int bif_add_bin(struct bif_entry *bf)
535{
536 size_t size;
537 char *bin = read_full_file(bf->filename, &size);
538
539 if (!bf->dest_dev)
540 bf->dest_dev = PART_ATTR_DEST_DEVICE_PS;
541
542 bf->flags |= 1ULL << BIF_FLAG_BIN_FILE;
543 return bif_add_part(bf, bin, size);
544}
545
546/* Add elf file */
547static char *elf2flat64(char *elf, size_t *flat_size, size_t *load_addr)
548{
549 Elf64_Ehdr *ehdr;
550 Elf64_Shdr *shdr;
551 size_t min_addr = -1, max_addr = 0;
552 char *flat;
553 int i;
554
555 ehdr = (void *)elf;
556 shdr = (void *)(elf + le64_to_cpu(ehdr->e_shoff));
557
558 /* Look for smallest / biggest address */
559 for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++, shdr++) {
560 if (!shdr->sh_size || !shdr->sh_addr ||
561 !(shdr->sh_flags & SHF_ALLOC) ||
562 (shdr->sh_type == SHT_NOBITS))
563 continue;
564
565 if (le64_to_cpu(shdr->sh_addr) < min_addr)
566 min_addr = le64_to_cpu(shdr->sh_addr);
567 if ((le64_to_cpu(shdr->sh_addr) + le64_to_cpu(shdr->sh_size)) >
568 max_addr)
569 max_addr = le64_to_cpu(shdr->sh_addr) +
570 le64_to_cpu(shdr->sh_size);
571 }
572
573 *load_addr = min_addr;
574 *flat_size = max_addr - min_addr;
575 flat = calloc(1, *flat_size);
576 if (!flat)
577 return NULL;
578
579 shdr = (void *)(elf + le64_to_cpu(ehdr->e_shoff));
580 for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++, shdr++) {
581 char *dst = flat + le64_to_cpu(shdr->sh_addr) - min_addr;
582 char *src = elf + le64_to_cpu(shdr->sh_offset);
583
584 if (!shdr->sh_size || !shdr->sh_addr ||
585 !(shdr->sh_flags & SHF_ALLOC))
586 continue;
587
588 if (shdr->sh_type != SHT_NOBITS)
589 memcpy(dst, src, le64_to_cpu(shdr->sh_size));
590 }
591
592 return flat;
593}
594
595static char *elf2flat32(char *elf, size_t *flat_size, size_t *load_addr)
596{
597 Elf32_Ehdr *ehdr;
598 Elf32_Shdr *shdr;
599 size_t min_addr = -1, max_addr = 0;
600 char *flat;
601 int i;
602
603 ehdr = (void *)elf;
604 shdr = (void *)(elf + le32_to_cpu(ehdr->e_shoff));
605
606 /* Look for smallest / biggest address */
607 for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++, shdr++) {
608 if (!shdr->sh_size || !shdr->sh_addr ||
609 !(shdr->sh_flags & SHF_ALLOC) ||
610 (shdr->sh_type == SHT_NOBITS))
611 continue;
612
613 if (le32_to_cpu(shdr->sh_addr) < min_addr)
614 min_addr = le32_to_cpu(shdr->sh_addr);
615 if ((le32_to_cpu(shdr->sh_addr) + le32_to_cpu(shdr->sh_size)) >
616 max_addr)
617 max_addr = le32_to_cpu(shdr->sh_addr) +
618 le32_to_cpu(shdr->sh_size);
619 }
620
621 *load_addr = min_addr;
622 *flat_size = max_addr - min_addr;
623 flat = calloc(1, *flat_size);
624 if (!flat)
625 return NULL;
626
627 shdr = (void *)(elf + le32_to_cpu(ehdr->e_shoff));
628 for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++, shdr++) {
629 char *dst = flat + le32_to_cpu(shdr->sh_addr) - min_addr;
630 char *src = elf + le32_to_cpu(shdr->sh_offset);
631
632 if (!shdr->sh_size || !shdr->sh_addr ||
633 !(shdr->sh_flags & SHF_ALLOC))
634 continue;
635
636 if (shdr->sh_type != SHT_NOBITS)
637 memcpy(dst, src, le32_to_cpu(shdr->sh_size));
638 }
639
640 return flat;
641}
642
643static int bif_add_elf(struct bif_entry *bf)
644{
645 size_t size;
646 size_t elf_size;
647 char *elf;
648 char *flat;
649 size_t load_addr;
650 Elf32_Ehdr *ehdr32;
651 Elf64_Ehdr *ehdr64;
652
653 elf = read_full_file(bf->filename, &elf_size);
654 if (!elf)
655 return -1;
656
657 ehdr32 = (void *)elf;
658 ehdr64 = (void *)elf;
659
660 switch (ehdr32->e_ident[EI_CLASS]) {
661 case ELFCLASS32:
662 flat = elf2flat32(elf, &size, &load_addr);
663 bf->entry = le32_to_cpu(ehdr32->e_entry);
664 bf->flags |= 1ULL << BIF_FLAG_AARCH32;
665 break;
666 case ELFCLASS64:
667 flat = elf2flat64(elf, &size, &load_addr);
668 bf->entry = le64_to_cpu(ehdr64->e_entry);
669 break;
670 default:
671 printf("Unknown ELF class: %d\n", ehdr32->e_ident[EI_CLASS]);
672 return -1;
673 }
674
675 if (!flat)
676 return -1;
677
678 bf->load = load_addr;
679 if (!bf->dest_dev)
680 bf->dest_dev = PART_ATTR_DEST_DEVICE_PS;
681
682 bf->flags |= 1ULL << BIF_FLAG_ELF_FILE;
683 return bif_add_part(bf, flat, size);
684}
685
686static const struct bif_file_type bif_file_types[] = {
687 {
688 .name = "bitstream (.bit)",
689 .header = 0x00090ff0,
690 .add = bif_add_bit,
691 },
692
693 {
694 .name = "ELF",
695 .header = 0x7f454c46,
696 .add = bif_add_elf,
697 },
698
699 /* Anything else is a .bin file */
700 {
701 .name = ".bin",
702 .add = bif_add_bin,
703 },
704};
705
706static int bif_fsbl_config(struct bif_entry *fsbl_config,
707 struct bif_entry *entries, int nr_entries)
708{
709 int i;
710 int config_set = 0;
711 struct {
712 const char *name;
713 uint64_t flags;
714 uint64_t dest_cpu;
715 } configs[] = {
716 { .name = "a5x_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 },
717 { .name = "a53_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 },
718 { .name = "a5x_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0,
719 .flags = 1ULL << BIF_FLAG_AARCH32 },
720 { .name = "a53_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0,
721 .flags = 1ULL << BIF_FLAG_AARCH32 },
722 { .name = "r5_single", .dest_cpu = PART_ATTR_DEST_CPU_R5_0 },
723 { .name = "r5_dual", .dest_cpu = PART_ATTR_DEST_CPU_R5_L },
724 };
725
726 /* Set target CPU of bootloader entry */
727 for (i = 0; i < nr_entries; i++) {
728 struct bif_entry *b = &entries[i];
729 const char *config_attr = fsbl_config->filename;
730 int j;
731
732 if (!(b->flags & (1ULL << BIF_FLAG_BOOTLOADER)))
733 continue;
734
735 for (j = 0; j < ARRAY_SIZE(configs); j++) {
736 if (!strncmp(config_attr, configs[j].name,
737 strlen(configs[j].name))) {
738 b->dest_cpu = configs[j].dest_cpu;
739 b->flags |= configs[j].flags;
740 config_set = 1;
741 }
742 }
743
744 if (!config_set) {
745 printf("ERROR: Unsupported fsbl_config: %s\n",
746 config_attr);
747 return -1;
748 }
749 }
750
751 if (!config_set) {
752 printf("ERROR: fsbl_config w/o bootloader\n");
753 return -1;
754 }
755
756 return 0;
757}
758
759static const struct bif_flags *find_flag(char *str)
760{
761 const struct bif_flags *bf;
762 int i;
763
764 for (i = 0; i < ARRAY_SIZE(bif_flags); i++) {
765 bf = &bif_flags[i];
766 if (!strncmp(bf->name, str, strlen(bf->name)))
767 return bf;
768 }
769
770 printf("ERROR: Flag '%s' not found\n", str);
771
772 return NULL;
773}
774
775static int bif_open_file(struct bif_entry *entry)
776{
777 int fd = open(entry->filename, O_RDONLY);
778
779 if (fd < 0)
780 printf("Error opening file %s\n", entry->filename);
781
782 return fd;
783}
784
785static const struct bif_file_type *get_file_type(struct bif_entry *entry)
786{
787 int fd = bif_open_file(entry);
788 uint32_t header;
789 int i;
790
791 if (fd < 0)
792 return NULL;
793
794 if (read(fd, &header, sizeof(header)) != sizeof(header)) {
795 printf("Error reading file %s", entry->filename);
796 return NULL;
797 }
798
799 close(fd);
800
801 for (i = 0; i < ARRAY_SIZE(bif_file_types); i++) {
802 const struct bif_file_type *type = &bif_file_types[i];
803
804 if (!type->header)
805 return type;
806 if (type->header == be32_to_cpu(header))
807 return type;
808 }
809
810 return NULL;
811}
812
813#define NEXT_CHAR(str, chr) ({ \
814 char *_n = strchr(str, chr); \
815 if (!_n) \
816 goto err; \
817 _n; \
818})
819
820static char *skip_whitespace(char *str)
821{
822 while (*str == ' ' || *str == '\t')
823 str++;
824
825 return str;
826}
827
828int zynqmpbif_copy_image(int outfd, struct image_tool_params *mparams)
829{
830 char *bif, *bifp, *bifpn;
831 char *line;
832 struct bif_entry entries[32] = { { 0 } };
833 int nr_entries = 0;
834 struct bif_entry *entry = entries;
835 size_t len;
836 int i;
837 uint32_t csum;
838 int bldr = -1;
839
840 bif_init();
841
842 /* Read .bif input file */
843 bif = read_full_file(mparams->datafile, NULL);
844 if (!bif)
845 goto err;
846
847 /* Interpret .bif file */
848 bifp = bif;
849
850 /* A bif description starts with a { section */
851 bifp = NEXT_CHAR(bifp, '{') + 1;
852
853 /* Read every line */
854 while (1) {
855 bifpn = NEXT_CHAR(bifp, '\n');
856
857 if (bifpn[-1] == '\r')
858 bifpn[-1] = '\0';
859
860 *bifpn = '\0';
861 bifpn++;
862 line = bifp;
863
864 line = skip_whitespace(line);
865
866 /* Attributes? */
867 if (*line == '[') {
868 line++;
869 while (1) {
870 const struct bif_flags *bf;
871
872 line = skip_whitespace(line);
873 bf = find_flag(line);
874 if (!bf)
875 goto err;
876
877 line += strlen(bf->name);
878 if (bf->parse)
879 line = bf->parse(line, entry);
880 else
881 entry->flags |= 1ULL << bf->flag;
882
883 if (!line)
884 goto err;
885
886 /* Go to next attribute or quit */
887 if (*line == ']') {
888 line++;
889 break;
890 }
891 if (*line == ',')
892 line++;
893 }
894 }
895
896 /* End of image description */
897 if (*line == '}')
898 break;
899
900 if (*line) {
901 line = skip_whitespace(line);
902 entry->filename = line;
903 nr_entries++;
904 entry++;
905 }
906
907 /* Use next line */
908 bifp = bifpn;
909 }
910
911 for (i = 0; i < nr_entries; i++) {
912 debug("Entry flags=%#lx name=%s\n", entries[i].flags,
913 entries[i].filename);
914 }
915
916 /*
917 * Some entries are actually configuration option for other ones,
918 * let's apply them in an intermediate step.
919 */
920 for (i = 0; i < nr_entries; i++) {
921 struct bif_entry *entry = &entries[i];
922
923 if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG))
924 if (bif_fsbl_config(entry, entries, nr_entries))
925 goto err;
926 }
927
928 /* Make sure PMUFW comes before bootloader */
929 for (i = 0; i < nr_entries; i++) {
930 struct bif_entry *entry = &entries[i];
931
932 if (entry->flags & (1ULL << BIF_FLAG_BOOTLOADER))
933 bldr = i;
934 if (entry->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE)) {
935 if (bldr >= 0) {
936 struct bif_entry tmp = *entry;
937
938 *entry = entries[bldr];
939 entries[bldr] = tmp;
940 }
941 }
942 }
943
944 for (i = 0; i < nr_entries; i++) {
945 struct bif_entry *entry = &entries[i];
946 const struct bif_file_type *type;
947 int r;
948
949 if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG))
950 continue;
951
952 type = get_file_type(entry);
953 if (!type)
954 goto err;
955
956 debug("type=%s file=%s\n", type->name, entry->filename);
957 r = type->add(entry);
958 if (r)
959 goto err;
960 }
961
962 /* Calculate checksums */
963 csum = zynqmp_csum(&bif_output.header->width_detection,
964 &bif_output.header->checksum);
965 bif_output.header->checksum = cpu_to_le32(csum);
966
967 if (bif_output.imgheader) {
968 csum = zynqmp_csum(bif_output.imgheader,
969 &bif_output.imgheader->checksum);
970 bif_output.imgheader->checksum = cpu_to_le32(csum);
971 }
972
973 /* Write headers and components */
974 if (lseek(outfd, 0, SEEK_SET) != 0)
975 goto err;
976
977 len = bif_output.data_len;
978 bifp = bif_output.data;
979 while (len) {
980 int r;
981
982 r = write(outfd, bifp, len);
983 if (r < 0)
984 goto err;
985 len -= r;
986 bifp += r;
987 }
988
989 return 0;
990
991err:
992 fprintf(stderr, "Error: Failed to create image.\n");
993 return -1;
994}
995
996/* Needs to be stubbed out so we can print after creation */
997static void zynqmpbif_set_header(void *ptr, struct stat *sbuf, int ifd,
998 struct image_tool_params *params)
999{
1000}
1001
1002static struct zynqmp_header zynqmpimage_header;
1003
1004U_BOOT_IMAGE_TYPE(
1005 zynqmpbif,
1006 "Xilinx ZynqMP Boot Image support (bif)",
1007 sizeof(struct zynqmp_header),
1008 (void *)&zynqmpimage_header,
1009 zynqmpbif_check_params,
1010 NULL,
1011 zynqmpimage_print_header,
1012 zynqmpbif_set_header,
1013 NULL,
1014 zynqmpbif_check_image_types,
1015 NULL,
1016 NULL
1017);