]> git.sur5r.net Git - u-boot/blob - tools/zynqmpbif.c
Merge tag 'xilinx-for-v2018.07-2' of git://www.denx.de/git/u-boot-microblaze
[u-boot] / tools / zynqmpbif.c
1 /*
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
13 struct 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
24 enum 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
52 struct bif_flags {
53         const char name[32];
54         uint64_t flag;
55         char *(*parse)(char *line, struct bif_entry *bf);
56 };
57
58 struct bif_file_type {
59         const char name[32];
60         uint32_t header;
61         int (*add)(struct bif_entry *bf);
62 };
63
64 struct 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
72 struct bif_output bif_output;
73
74 static 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
87 static 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
105 static int zynqmpbif_check_image_types(uint8_t type)
106 {
107         return (type == IH_TYPE_ZYNQMPBIF) ? EXIT_SUCCESS : EXIT_FAILURE;
108 }
109
110 static 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
135 static 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
150 static 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
159 static 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
168 static 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
177 static 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
193 static 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
206 static 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
240 static 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
282 static 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
298 static 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
319 static int bif_add_part(struct bif_entry *bf, const char *data, size_t len)
320 {
321         size_t parthdr_offset = 0;
322         struct partition_header parthdr = {
323                 .len_enc = cpu_to_le32(len / 4),
324                 .len_unenc = cpu_to_le32(len / 4),
325                 .len = cpu_to_le32(len / 4),
326                 .entry_point = cpu_to_le64(bf->entry),
327                 .load_address = cpu_to_le64(bf->load),
328         };
329         int r;
330         uint32_t csum;
331
332         if (bf->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE))
333                 return bif_add_pmufw(bf, data, len);
334
335         r = bif_add_blob(data, len, &bf->offset);
336         if (r)
337                 return r;
338
339         parthdr.offset = cpu_to_le32(bf->offset / 4);
340
341         if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) {
342                 if (bif_output.last_part) {
343                         printf("ERROR: Bootloader expected before others\n");
344                         return -1;
345                 }
346
347                 parthdr.offset = cpu_to_le32(bif_output.header->image_offset);
348                 parthdr.len = cpu_to_le32((bf->offset + len -
349                         bif_output.header->image_offset) / 4);
350                 parthdr.len_enc = parthdr.len;
351                 parthdr.len_unenc = parthdr.len;
352         }
353
354         /* Normalize EL */
355         bf->exp_lvl = bf->exp_lvl ? bf->exp_lvl - 1 : 3;
356         parthdr.attributes |= bf->exp_lvl << PART_ATTR_TARGET_EL_SHIFT;
357         parthdr.attributes |= bf->dest_dev;
358         parthdr.attributes |= bf->dest_cpu;
359         if (bf->flags & (1ULL << BIF_FLAG_TZ))
360                 parthdr.attributes |= PART_ATTR_TZ_SECURE;
361         if (bf->flags & (1ULL << BIF_FLAG_PART_OWNER_UBOOT))
362                 parthdr.attributes |= PART_ATTR_PART_OWNER_UBOOT;
363         switch (bf->dest_cpu) {
364         case PART_ATTR_DEST_CPU_NONE:
365         case PART_ATTR_DEST_CPU_A53_0:
366         case PART_ATTR_DEST_CPU_A53_1:
367         case PART_ATTR_DEST_CPU_A53_2:
368         case PART_ATTR_DEST_CPU_A53_3:
369                 if (bf->flags & (1ULL << BIF_FLAG_AARCH32))
370                         parthdr.attributes |= PART_ATTR_A53_EXEC_AARCH32;
371         }
372
373         csum = zynqmp_csum(&parthdr, &parthdr.checksum);
374         parthdr.checksum = cpu_to_le32(csum);
375
376         r = bif_add_blob(&parthdr, sizeof(parthdr), &parthdr_offset);
377         if (r)
378                 return r;
379
380         /* Add image header table if not there yet */
381         if (!bif_output.imgheader) {
382                 size_t imghdr_off = 0;
383                 struct image_header_table imghdr = {
384                         .version = cpu_to_le32(0x01020000),
385                         .nr_parts = 0,
386                 };
387
388                 r = bif_add_blob(&imghdr, sizeof(imghdr), &imghdr_off);
389                 if (r)
390                         return r;
391
392                 bif_output.header->image_header_table_offset = imghdr_off;
393                 bif_output.imgheader = (void *)(bif_output.data + imghdr_off);
394         }
395
396         bif_output.imgheader->nr_parts = cpu_to_le32(le32_to_cpu(
397                 bif_output.imgheader->nr_parts) + 1);
398
399         /* Link to this partition header */
400         if (bif_output.last_part) {
401                 bif_output.last_part->next_partition_offset =
402                         cpu_to_le32(parthdr_offset / 4);
403
404                 /* Recalc checksum of last_part */
405                 csum = zynqmp_csum(bif_output.last_part,
406                                    &bif_output.last_part->checksum);
407                 bif_output.last_part->checksum = cpu_to_le32(csum);
408         } else {
409                 bif_output.imgheader->partition_header_offset =
410                         cpu_to_le32(parthdr_offset / 4);
411         }
412         bif_output.last_part = (void *)(bif_output.data + parthdr_offset);
413
414         if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) {
415                 bif_output.header->image_load = cpu_to_le32(bf->load);
416                 if (!bif_output.header->image_offset)
417                         bif_output.header->image_offset =
418                                 cpu_to_le32(bf->offset);
419                 bif_output.header->image_size = cpu_to_le32(len);
420                 bif_output.header->image_stored_size = cpu_to_le32(len);
421
422                 bif_output.header->image_attributes &= ~HEADER_CPU_SELECT_MASK;
423                 switch (bf->dest_cpu) {
424                 default:
425                 case PART_ATTR_DEST_CPU_A53_0:
426                         if (bf->flags & BIF_FLAG_AARCH32)
427                                 bif_output.header->image_attributes |=
428                                         HEADER_CPU_SELECT_A53_32BIT;
429                         else
430                                 bif_output.header->image_attributes |=
431                                         HEADER_CPU_SELECT_A53_64BIT;
432                         break;
433                 case PART_ATTR_DEST_CPU_R5_0:
434                         bif_output.header->image_attributes |=
435                                 HEADER_CPU_SELECT_R5_SINGLE;
436                         break;
437                 case PART_ATTR_DEST_CPU_R5_L:
438                         bif_output.header->image_attributes |=
439                                 HEADER_CPU_SELECT_R5_DUAL;
440                         break;
441                 }
442         }
443
444         return 0;
445 }
446
447 /* Add .bit bitstream */
448 static int bif_add_bit(struct bif_entry *bf)
449 {
450         char *bit = read_full_file(bf->filename, NULL);
451         char *bitbin;
452         uint8_t initial_header[] = { 0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f,
453                                      0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01, 0x61 };
454         uint16_t len;
455         uint32_t bitlen;
456         int i;
457
458         if (!bit)
459                 return -1;
460
461         /* Skip initial header */
462         if (memcmp(bit, initial_header, sizeof(initial_header)))
463                 return -1;
464
465         bit += sizeof(initial_header);
466
467         /* Design name */
468         len = be16_to_cpu(*(uint16_t *)bit);
469         bit += sizeof(uint16_t);
470         debug("Design: %s\n", bit);
471         bit += len;
472
473         /* Device identifier */
474         if (*bit != 'b')
475                 return -1;
476         bit++;
477         len = be16_to_cpu(*(uint16_t *)bit);
478         bit += sizeof(uint16_t);
479         debug("Device: %s\n", bit);
480         bit += len;
481
482         /* Date */
483         if (*bit != 'c')
484                 return -1;
485         bit++;
486         len = be16_to_cpu(*(uint16_t *)bit);
487         bit += sizeof(uint16_t);
488         debug("Date: %s\n", bit);
489         bit += len;
490
491         /* Time */
492         if (*bit != 'd')
493                 return -1;
494         bit++;
495         len = be16_to_cpu(*(uint16_t *)bit);
496         bit += sizeof(uint16_t);
497         debug("Time: %s\n", bit);
498         bit += len;
499
500         /* Bitstream length */
501         if (*bit != 'e')
502                 return -1;
503         bit++;
504         bitlen = be32_to_cpu(*(uint32_t *)bit);
505         bit += sizeof(uint32_t);
506         bitbin = bit;
507
508         debug("Bitstream Length: 0x%x\n", bitlen);
509         for (i = 0; i < bitlen; i += sizeof(uint32_t)) {
510                 uint32_t *bitbin32 = (uint32_t *)&bitbin[i];
511                 *bitbin32 = __swab32(*bitbin32);
512         }
513
514         if (!bf->dest_dev)
515                 bf->dest_dev = PART_ATTR_DEST_DEVICE_PL;
516
517         bf->load = 0xffffffff;
518         bf->entry = 0;
519
520         bf->flags |= 1ULL << BIF_FLAG_BIT_FILE;
521         return bif_add_part(bf, bit, bitlen);
522 }
523
524 /* Add .bin bitstream */
525 static int bif_add_bin(struct bif_entry *bf)
526 {
527         size_t size;
528         char *bin = read_full_file(bf->filename, &size);
529
530         if (!bf->dest_dev)
531                 bf->dest_dev = PART_ATTR_DEST_DEVICE_PS;
532
533         bf->flags |= 1ULL << BIF_FLAG_BIN_FILE;
534         return bif_add_part(bf, bin, size);
535 }
536
537 /* Add elf file */
538 static char *elf2flat64(char *elf, size_t *flat_size, size_t *load_addr)
539 {
540         Elf64_Ehdr *ehdr;
541         Elf64_Shdr *shdr;
542         size_t min_addr = -1, max_addr = 0;
543         char *flat;
544         int i;
545
546         ehdr = (void *)elf;
547         shdr = (void *)(elf + le64_to_cpu(ehdr->e_shoff));
548
549         /* Look for smallest / biggest address */
550         for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++, shdr++) {
551                 if (!shdr->sh_size || !shdr->sh_addr ||
552                     !(shdr->sh_flags & SHF_ALLOC) ||
553                     (shdr->sh_type == SHT_NOBITS))
554                         continue;
555
556                 if (le64_to_cpu(shdr->sh_addr) < min_addr)
557                         min_addr = le64_to_cpu(shdr->sh_addr);
558                 if ((le64_to_cpu(shdr->sh_addr) + le64_to_cpu(shdr->sh_size)) >
559                         max_addr)
560                         max_addr = le64_to_cpu(shdr->sh_addr) +
561                                    le64_to_cpu(shdr->sh_size);
562         }
563
564         *load_addr = min_addr;
565         *flat_size = max_addr - min_addr;
566         flat = calloc(1, *flat_size);
567         if (!flat)
568                 return NULL;
569
570         shdr = (void *)(elf + le64_to_cpu(ehdr->e_shoff));
571         for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++, shdr++) {
572                 char *dst = flat + le64_to_cpu(shdr->sh_addr) - min_addr;
573                 char *src = elf + le64_to_cpu(shdr->sh_offset);
574
575                 if (!shdr->sh_size || !shdr->sh_addr ||
576                     !(shdr->sh_flags & SHF_ALLOC))
577                         continue;
578
579                 if (shdr->sh_type != SHT_NOBITS)
580                         memcpy(dst, src, le64_to_cpu(shdr->sh_size));
581         }
582
583         return flat;
584 }
585
586 static char *elf2flat32(char *elf, size_t *flat_size, size_t *load_addr)
587 {
588         Elf32_Ehdr *ehdr;
589         Elf32_Shdr *shdr;
590         size_t min_addr = -1, max_addr = 0;
591         char *flat;
592         int i;
593
594         ehdr = (void *)elf;
595         shdr = (void *)(elf + le32_to_cpu(ehdr->e_shoff));
596
597         /* Look for smallest / biggest address */
598         for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++, shdr++) {
599                 if (!shdr->sh_size || !shdr->sh_addr ||
600                     !(shdr->sh_flags & SHF_ALLOC) ||
601                     (shdr->sh_type == SHT_NOBITS))
602                         continue;
603
604                 if (le32_to_cpu(shdr->sh_addr) < min_addr)
605                         min_addr = le32_to_cpu(shdr->sh_addr);
606                 if ((le32_to_cpu(shdr->sh_addr) + le32_to_cpu(shdr->sh_size)) >
607                         max_addr)
608                         max_addr = le32_to_cpu(shdr->sh_addr) +
609                                    le32_to_cpu(shdr->sh_size);
610         }
611
612         *load_addr = min_addr;
613         *flat_size = max_addr - min_addr;
614         flat = calloc(1, *flat_size);
615         if (!flat)
616                 return NULL;
617
618         shdr = (void *)(elf + le32_to_cpu(ehdr->e_shoff));
619         for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++, shdr++) {
620                 char *dst = flat + le32_to_cpu(shdr->sh_addr) - min_addr;
621                 char *src = elf + le32_to_cpu(shdr->sh_offset);
622
623                 if (!shdr->sh_size || !shdr->sh_addr ||
624                     !(shdr->sh_flags & SHF_ALLOC))
625                         continue;
626
627                 if (shdr->sh_type != SHT_NOBITS)
628                         memcpy(dst, src, le32_to_cpu(shdr->sh_size));
629         }
630
631         return flat;
632 }
633
634 static int bif_add_elf(struct bif_entry *bf)
635 {
636         size_t size;
637         size_t elf_size;
638         char *elf;
639         char *flat;
640         size_t load_addr;
641         Elf32_Ehdr *ehdr32;
642         Elf64_Ehdr *ehdr64;
643
644         elf = read_full_file(bf->filename, &elf_size);
645         if (!elf)
646                 return -1;
647
648         ehdr32 = (void *)elf;
649         ehdr64 = (void *)elf;
650
651         switch (ehdr32->e_ident[EI_CLASS]) {
652         case ELFCLASS32:
653                 flat = elf2flat32(elf, &size, &load_addr);
654                 bf->entry = le32_to_cpu(ehdr32->e_entry);
655                 bf->flags |= 1ULL << BIF_FLAG_AARCH32;
656                 break;
657         case ELFCLASS64:
658                 flat = elf2flat64(elf, &size, &load_addr);
659                 bf->entry = le64_to_cpu(ehdr64->e_entry);
660                 break;
661         default:
662                 printf("Unknown ELF class: %d\n", ehdr32->e_ident[EI_CLASS]);
663                 return -1;
664         }
665
666         if (!flat)
667                 return -1;
668
669         bf->load = load_addr;
670         if (!bf->dest_dev)
671                 bf->dest_dev = PART_ATTR_DEST_DEVICE_PS;
672
673         bf->flags |= 1ULL << BIF_FLAG_ELF_FILE;
674         return bif_add_part(bf, flat, size);
675 }
676
677 static const struct bif_file_type bif_file_types[] = {
678         {
679                 .name = "bitstream (.bit)",
680                 .header = 0x00090ff0,
681                 .add = bif_add_bit,
682         },
683
684         {
685                 .name = "ELF",
686                 .header = 0x7f454c46,
687                 .add = bif_add_elf,
688         },
689
690         /* Anything else is a .bin file */
691         {
692                 .name = ".bin",
693                 .add = bif_add_bin,
694         },
695 };
696
697 static int bif_fsbl_config(struct bif_entry *fsbl_config,
698                            struct bif_entry *entries, int nr_entries)
699 {
700         int i;
701         int config_set = 0;
702         struct {
703                 const char *name;
704                 uint64_t flags;
705                 uint64_t dest_cpu;
706         } configs[] = {
707                 { .name = "a5x_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 },
708                 { .name = "a53_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 },
709                 { .name = "a5x_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0,
710                                      .flags = 1ULL << BIF_FLAG_AARCH32 },
711                 { .name = "a53_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0,
712                                      .flags = 1ULL << BIF_FLAG_AARCH32 },
713                 { .name = "r5_single", .dest_cpu = PART_ATTR_DEST_CPU_R5_0 },
714                 { .name = "r5_dual", .dest_cpu = PART_ATTR_DEST_CPU_R5_L },
715         };
716
717         /* Set target CPU of bootloader entry */
718         for (i = 0; i < nr_entries; i++) {
719                 struct bif_entry *b = &entries[i];
720                 const char *config_attr = fsbl_config->filename;
721                 int j;
722
723                 if (!(b->flags & (1ULL << BIF_FLAG_BOOTLOADER)))
724                         continue;
725
726                 for (j = 0; j < ARRAY_SIZE(configs); j++) {
727                         if (!strncmp(config_attr, configs[j].name,
728                                      strlen(configs[j].name))) {
729                                 b->dest_cpu = configs[j].dest_cpu;
730                                 b->flags |= configs[j].flags;
731                                 config_set = 1;
732                         }
733                 }
734
735                 if (!config_set) {
736                         printf("ERROR: Unsupported fsbl_config: %s\n",
737                                config_attr);
738                         return -1;
739                 }
740         }
741
742         if (!config_set) {
743                 printf("ERROR: fsbl_config w/o bootloader\n");
744                 return -1;
745         }
746
747         return 0;
748 }
749
750 static const struct bif_flags *find_flag(char *str)
751 {
752         const struct bif_flags *bf;
753         int i;
754
755         for (i = 0; i < ARRAY_SIZE(bif_flags); i++) {
756                 bf = &bif_flags[i];
757                 if (!strncmp(bf->name, str, strlen(bf->name)))
758                         return bf;
759         }
760
761         printf("ERROR: Flag '%s' not found\n", str);
762
763         return NULL;
764 }
765
766 static int bif_open_file(struct bif_entry *entry)
767 {
768         int fd = open(entry->filename, O_RDONLY);
769
770         if (fd < 0)
771                 printf("Error opening file %s\n", entry->filename);
772
773         return fd;
774 }
775
776 static const struct bif_file_type *get_file_type(struct bif_entry *entry)
777 {
778         int fd = bif_open_file(entry);
779         uint32_t header;
780         int i;
781
782         if (fd < 0)
783                 return NULL;
784
785         if (read(fd, &header, sizeof(header)) != sizeof(header)) {
786                 printf("Error reading file %s", entry->filename);
787                 return NULL;
788         }
789
790         close(fd);
791
792         for (i = 0; i < ARRAY_SIZE(bif_file_types); i++) {
793                 const struct bif_file_type *type = &bif_file_types[i];
794
795                 if (!type->header)
796                         return type;
797                 if (type->header == be32_to_cpu(header))
798                         return type;
799         }
800
801         return NULL;
802 }
803
804 #define NEXT_CHAR(str, chr) ({          \
805         char *_n = strchr(str, chr);    \
806         if (!_n)                        \
807                 goto err;               \
808         _n;                             \
809 })
810
811 static char *skip_whitespace(char *str)
812 {
813         while (*str == ' ' || *str == '\t')
814                 str++;
815
816         return str;
817 }
818
819 int zynqmpbif_copy_image(int outfd, struct image_tool_params *mparams)
820 {
821         char *bif, *bifp, *bifpn;
822         char *line;
823         struct bif_entry entries[32] = { { 0 } };
824         int nr_entries = 0;
825         struct bif_entry *entry = entries;
826         size_t len;
827         int i;
828         uint32_t csum;
829         int bldr = -1;
830
831         bif_init();
832
833         /* Read .bif input file */
834         bif = read_full_file(mparams->datafile, NULL);
835         if (!bif)
836                 goto err;
837
838         /* Interpret .bif file */
839         bifp = bif;
840
841         /* A bif description starts with a { section */
842         bifp = NEXT_CHAR(bifp, '{') + 1;
843
844         /* Read every line */
845         while (1) {
846                 bifpn = NEXT_CHAR(bifp, '\n');
847
848                 if (bifpn[-1] == '\r')
849                         bifpn[-1] = '\0';
850
851                 *bifpn = '\0';
852                 bifpn++;
853                 line = bifp;
854
855                 line = skip_whitespace(line);
856
857                 /* Attributes? */
858                 if (*line == '[') {
859                         line++;
860                         while (1) {
861                                 const struct bif_flags *bf;
862
863                                 line = skip_whitespace(line);
864                                 bf = find_flag(line);
865                                 if (!bf)
866                                         goto err;
867
868                                 line += strlen(bf->name);
869                                 if (bf->parse)
870                                         line = bf->parse(line, entry);
871                                 else
872                                         entry->flags |= 1ULL << bf->flag;
873
874                                 if (!line)
875                                         goto err;
876
877                                 /* Go to next attribute or quit */
878                                 if (*line == ']') {
879                                         line++;
880                                         break;
881                                 }
882                                 if (*line == ',')
883                                         line++;
884                         }
885                 }
886
887                 /* End of image description */
888                 if (*line == '}')
889                         break;
890
891                 if (*line) {
892                         line = skip_whitespace(line);
893                         entry->filename = line;
894                         nr_entries++;
895                         entry++;
896                 }
897
898                 /* Use next line */
899                 bifp = bifpn;
900         }
901
902         for (i = 0; i < nr_entries; i++) {
903                 debug("Entry flags=%#lx name=%s\n", entries[i].flags,
904                       entries[i].filename);
905         }
906
907         /*
908          * Some entries are actually configuration option for other ones,
909          * let's apply them in an intermediate step.
910          */
911         for (i = 0; i < nr_entries; i++) {
912                 struct bif_entry *entry = &entries[i];
913
914                 if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG))
915                         if (bif_fsbl_config(entry, entries, nr_entries))
916                                 goto err;
917         }
918
919         /* Make sure PMUFW comes before bootloader */
920         for (i = 0; i < nr_entries; i++) {
921                 struct bif_entry *entry = &entries[i];
922
923                 if (entry->flags & (1ULL << BIF_FLAG_BOOTLOADER))
924                         bldr = i;
925                 if (entry->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE)) {
926                         if (bldr >= 0) {
927                                 struct bif_entry tmp = *entry;
928
929                                 *entry = entries[bldr];
930                                 entries[bldr] = tmp;
931                         }
932                 }
933         }
934
935         for (i = 0; i < nr_entries; i++) {
936                 struct bif_entry *entry = &entries[i];
937                 const struct bif_file_type *type;
938                 int r;
939
940                 if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG))
941                         continue;
942
943                 type = get_file_type(entry);
944                 if (!type)
945                         goto err;
946
947                 debug("type=%s file=%s\n", type->name, entry->filename);
948                 r = type->add(entry);
949                 if (r)
950                         goto err;
951         }
952
953         /* Calculate checksums */
954         csum = zynqmp_csum(&bif_output.header->width_detection,
955                            &bif_output.header->checksum);
956         bif_output.header->checksum = cpu_to_le32(csum);
957
958         if (bif_output.imgheader) {
959                 csum = zynqmp_csum(bif_output.imgheader,
960                                    &bif_output.imgheader->checksum);
961                 bif_output.imgheader->checksum = cpu_to_le32(csum);
962         }
963
964         /* Write headers and components */
965         if (lseek(outfd, 0, SEEK_SET) != 0)
966                 goto err;
967
968         len = bif_output.data_len;
969         bifp = bif_output.data;
970         while (len) {
971                 int r;
972
973                 r = write(outfd, bifp, len);
974                 if (r < 0)
975                         goto err;
976                 len -= r;
977                 bifp += r;
978         }
979
980         return 0;
981
982 err:
983         fprintf(stderr, "Error: Failed to create image.\n");
984         return -1;
985 }
986
987 /* Needs to be stubbed out so we can print after creation */
988 static void zynqmpbif_set_header(void *ptr, struct stat *sbuf, int ifd,
989                                  struct image_tool_params *params)
990 {
991 }
992
993 static struct zynqmp_header zynqmpimage_header;
994
995 U_BOOT_IMAGE_TYPE(
996         zynqmpbif,
997         "Xilinx ZynqMP Boot Image support (bif)",
998         sizeof(struct zynqmp_header),
999         (void *)&zynqmpimage_header,
1000         zynqmpbif_check_params,
1001         NULL,
1002         zynqmpimage_print_header,
1003         zynqmpbif_set_header,
1004         NULL,
1005         zynqmpbif_check_image_types,
1006         NULL,
1007         NULL
1008 );