16915dcf3SAlexander Graf /* 26915dcf3SAlexander Graf * Copyright (C) 2018 Alexander Graf <agraf@suse.de> 36915dcf3SAlexander Graf * 46915dcf3SAlexander Graf * SPDX-License-Identifier: GPL-2.0+ 56915dcf3SAlexander Graf */ 66915dcf3SAlexander Graf 76915dcf3SAlexander Graf #include "imagetool.h" 86915dcf3SAlexander Graf #include "mkimage.h" 96915dcf3SAlexander Graf #include "zynqmpimage.h" 106915dcf3SAlexander Graf #include <elf.h> 116915dcf3SAlexander Graf #include <image.h> 126915dcf3SAlexander Graf 136915dcf3SAlexander Graf struct bif_entry { 146915dcf3SAlexander Graf const char *filename; 156915dcf3SAlexander Graf uint64_t flags; 166915dcf3SAlexander Graf uint64_t dest_cpu; 176915dcf3SAlexander Graf uint64_t exp_lvl; 186915dcf3SAlexander Graf uint64_t dest_dev; 196915dcf3SAlexander Graf uint64_t load; 206915dcf3SAlexander Graf uint64_t entry; 216915dcf3SAlexander Graf size_t offset; 226915dcf3SAlexander Graf }; 236915dcf3SAlexander Graf 246915dcf3SAlexander Graf enum bif_flag { 256915dcf3SAlexander Graf BIF_FLAG_AESKEYFILE, 266915dcf3SAlexander Graf BIF_FLAG_INIT, 276915dcf3SAlexander Graf BIF_FLAG_UDF_BH, 286915dcf3SAlexander Graf BIF_FLAG_HEADERSIGNATURE, 296915dcf3SAlexander Graf BIF_FLAG_PPKFILE, 306915dcf3SAlexander Graf BIF_FLAG_PSKFILE, 316915dcf3SAlexander Graf BIF_FLAG_SPKFILE, 326915dcf3SAlexander Graf BIF_FLAG_SSKFILE, 336915dcf3SAlexander Graf BIF_FLAG_SPKSIGNATURE, 346915dcf3SAlexander Graf BIF_FLAG_FSBL_CONFIG, 356915dcf3SAlexander Graf BIF_FLAG_AUTH_PARAMS, 366915dcf3SAlexander Graf BIF_FLAG_KEYSRC_ENCRYPTION, 376915dcf3SAlexander Graf BIF_FLAG_PMUFW_IMAGE, 386915dcf3SAlexander Graf BIF_FLAG_BOOTLOADER, 396915dcf3SAlexander Graf BIF_FLAG_TZ, 406915dcf3SAlexander Graf BIF_FLAG_BH_KEY_IV, 416915dcf3SAlexander Graf BIF_FLAG_BH_KEYFILE, 426915dcf3SAlexander Graf BIF_FLAG_PUF_FILE, 436915dcf3SAlexander Graf BIF_FLAG_AARCH32, 446915dcf3SAlexander Graf BIF_FLAG_PART_OWNER_UBOOT, 456915dcf3SAlexander Graf 466915dcf3SAlexander Graf /* Internal flags */ 476915dcf3SAlexander Graf BIF_FLAG_BIT_FILE, 486915dcf3SAlexander Graf BIF_FLAG_ELF_FILE, 496915dcf3SAlexander Graf BIF_FLAG_BIN_FILE, 506915dcf3SAlexander Graf }; 516915dcf3SAlexander Graf 526915dcf3SAlexander Graf struct bif_flags { 536915dcf3SAlexander Graf const char name[32]; 546915dcf3SAlexander Graf uint64_t flag; 556915dcf3SAlexander Graf char *(*parse)(char *line, struct bif_entry *bf); 566915dcf3SAlexander Graf }; 576915dcf3SAlexander Graf 586915dcf3SAlexander Graf struct bif_file_type { 596915dcf3SAlexander Graf const char name[32]; 606915dcf3SAlexander Graf uint32_t header; 616915dcf3SAlexander Graf int (*add)(struct bif_entry *bf); 626915dcf3SAlexander Graf }; 636915dcf3SAlexander Graf 646915dcf3SAlexander Graf struct bif_output { 656915dcf3SAlexander Graf size_t data_len; 666915dcf3SAlexander Graf char *data; 676915dcf3SAlexander Graf struct image_header_table *imgheader; 686915dcf3SAlexander Graf struct zynqmp_header *header; 696915dcf3SAlexander Graf struct partition_header *last_part; 706915dcf3SAlexander Graf }; 716915dcf3SAlexander Graf 726915dcf3SAlexander Graf struct bif_output bif_output; 736915dcf3SAlexander Graf 746915dcf3SAlexander Graf static uint32_t zynqmp_csum(void *start, void *end) 756915dcf3SAlexander Graf { 766915dcf3SAlexander Graf uint32_t checksum = 0; 776915dcf3SAlexander Graf uint32_t *ptr32 = start; 786915dcf3SAlexander Graf 796915dcf3SAlexander Graf while (ptr32 != end) { 806915dcf3SAlexander Graf checksum += le32_to_cpu(*ptr32); 816915dcf3SAlexander Graf ptr32++; 826915dcf3SAlexander Graf } 836915dcf3SAlexander Graf 846915dcf3SAlexander Graf return ~checksum; 856915dcf3SAlexander Graf } 866915dcf3SAlexander Graf 876915dcf3SAlexander Graf static int zynqmpbif_check_params(struct image_tool_params *params) 886915dcf3SAlexander Graf { 896915dcf3SAlexander Graf if (!params) 906915dcf3SAlexander Graf return 0; 916915dcf3SAlexander Graf 926915dcf3SAlexander Graf if (params->addr != 0x0) { 936915dcf3SAlexander Graf fprintf(stderr, "Error: Load Address can not be specified.\n"); 946915dcf3SAlexander Graf return -1; 956915dcf3SAlexander Graf } 966915dcf3SAlexander Graf 976915dcf3SAlexander Graf if (params->eflag) { 986915dcf3SAlexander Graf fprintf(stderr, "Error: Entry Point can not be specified.\n"); 996915dcf3SAlexander Graf return -1; 1006915dcf3SAlexander Graf } 1016915dcf3SAlexander Graf 1026915dcf3SAlexander Graf return !(params->lflag || params->dflag); 1036915dcf3SAlexander Graf } 1046915dcf3SAlexander Graf 1056915dcf3SAlexander Graf static int zynqmpbif_check_image_types(uint8_t type) 1066915dcf3SAlexander Graf { 1076915dcf3SAlexander Graf return (type == IH_TYPE_ZYNQMPBIF) ? EXIT_SUCCESS : EXIT_FAILURE; 1086915dcf3SAlexander Graf } 1096915dcf3SAlexander Graf 1106915dcf3SAlexander Graf static char *parse_dest_cpu(char *line, struct bif_entry *bf) 1116915dcf3SAlexander Graf { 1126915dcf3SAlexander Graf uint64_t i; 1136915dcf3SAlexander Graf 1146915dcf3SAlexander Graf for (i = 0; i < ARRAY_SIZE(dest_cpus); i++) { 1156915dcf3SAlexander Graf if (!strncmp(line, dest_cpus[i], strlen(dest_cpus[i]))) { 1166915dcf3SAlexander Graf bf->dest_cpu = i << PART_ATTR_DEST_CPU_SHIFT; 1176915dcf3SAlexander Graf return line + strlen(dest_cpus[i]); 1186915dcf3SAlexander Graf } 1196915dcf3SAlexander Graf 1206915dcf3SAlexander Graf /* a5x can also be written as a53 */ 1216915dcf3SAlexander Graf if (!strncmp(dest_cpus[i], "a5x", 3)) { 1226915dcf3SAlexander Graf char a53[] = "a53-X"; 1236915dcf3SAlexander Graf 1246915dcf3SAlexander Graf a53[4] = dest_cpus[i][4]; 1256915dcf3SAlexander Graf if (!strncmp(line, a53, strlen(a53))) { 1266915dcf3SAlexander Graf bf->dest_cpu = i << PART_ATTR_DEST_CPU_SHIFT; 1276915dcf3SAlexander Graf return line + strlen(a53); 1286915dcf3SAlexander Graf } 1296915dcf3SAlexander Graf } 1306915dcf3SAlexander Graf } 1316915dcf3SAlexander Graf 1326915dcf3SAlexander Graf return line; 1336915dcf3SAlexander Graf } 1346915dcf3SAlexander Graf 1356915dcf3SAlexander Graf static char *parse_el(char *line, struct bif_entry *bf) 1366915dcf3SAlexander Graf { 1376915dcf3SAlexander Graf const char *dest_els[] = { "none", "el-0", "el-1", "el-2", "el-3" }; 1386915dcf3SAlexander Graf int i; 1396915dcf3SAlexander Graf 1406915dcf3SAlexander Graf for (i = 0; i < ARRAY_SIZE(dest_els); i++) { 1416915dcf3SAlexander Graf if (!strncmp(line, dest_els[i], strlen(dest_els[i]))) { 1426915dcf3SAlexander Graf bf->exp_lvl = i; 1436915dcf3SAlexander Graf return line + strlen(dest_els[i]); 1446915dcf3SAlexander Graf } 1456915dcf3SAlexander Graf } 1466915dcf3SAlexander Graf 1476915dcf3SAlexander Graf return line; 1486915dcf3SAlexander Graf } 1496915dcf3SAlexander Graf 1506915dcf3SAlexander Graf static char *parse_load(char *line, struct bif_entry *bf) 1516915dcf3SAlexander Graf { 1526915dcf3SAlexander Graf char *endptr; 1536915dcf3SAlexander Graf 1546915dcf3SAlexander Graf bf->load = strtoll(line, &endptr, 0); 1556915dcf3SAlexander Graf 1566915dcf3SAlexander Graf return endptr; 1576915dcf3SAlexander Graf } 1586915dcf3SAlexander Graf 1596915dcf3SAlexander Graf static char *parse_entry(char *line, struct bif_entry *bf) 1606915dcf3SAlexander Graf { 1616915dcf3SAlexander Graf char *endptr; 1626915dcf3SAlexander Graf 1636915dcf3SAlexander Graf bf->entry = strtoll(line, &endptr, 0); 1646915dcf3SAlexander Graf 1656915dcf3SAlexander Graf return endptr; 1666915dcf3SAlexander Graf } 1676915dcf3SAlexander Graf 1686915dcf3SAlexander Graf static char *parse_offset(char *line, struct bif_entry *bf) 1696915dcf3SAlexander Graf { 1706915dcf3SAlexander Graf char *endptr; 1716915dcf3SAlexander Graf 1726915dcf3SAlexander Graf bf->offset = strtoll(line, &endptr, 0); 1736915dcf3SAlexander Graf 1746915dcf3SAlexander Graf return endptr; 1756915dcf3SAlexander Graf } 1766915dcf3SAlexander Graf 1776915dcf3SAlexander Graf static char *parse_partition_owner(char *line, struct bif_entry *bf) 1786915dcf3SAlexander Graf { 1796915dcf3SAlexander Graf char *endptr = NULL; 1806915dcf3SAlexander Graf 1816915dcf3SAlexander Graf if (!strncmp(line, "fsbl", 4)) { 1826915dcf3SAlexander Graf endptr = line + 4; 1836915dcf3SAlexander Graf } else if (!strncmp(line, "uboot", 5)) { 1846915dcf3SAlexander Graf bf->flags |= 1ULL << BIF_FLAG_PART_OWNER_UBOOT; 1856915dcf3SAlexander Graf endptr = line + 5; 1866915dcf3SAlexander Graf } else { 1876915dcf3SAlexander Graf printf("ERROR: Unknown partition type '%s'\n", line); 1886915dcf3SAlexander Graf } 1896915dcf3SAlexander Graf 1906915dcf3SAlexander Graf return endptr; 1916915dcf3SAlexander Graf } 1926915dcf3SAlexander Graf 1936915dcf3SAlexander Graf static const struct bif_flags bif_flags[] = { 1946915dcf3SAlexander Graf { "fsbl_config", BIF_FLAG_FSBL_CONFIG }, 1956915dcf3SAlexander Graf { "trustzone", BIF_FLAG_TZ }, 1966915dcf3SAlexander Graf { "pmufw_image", BIF_FLAG_PMUFW_IMAGE }, 1976915dcf3SAlexander Graf { "bootloader", BIF_FLAG_BOOTLOADER }, 1986915dcf3SAlexander Graf { "destination_cpu=", 0, parse_dest_cpu }, 1996915dcf3SAlexander Graf { "exception_level=", 0, parse_el }, 2006915dcf3SAlexander Graf { "load=", 0, parse_load }, 2016915dcf3SAlexander Graf { "startup=", 0, parse_entry }, 2026915dcf3SAlexander Graf { "offset=", 0, parse_offset }, 2036915dcf3SAlexander Graf { "partition_owner=", 0, parse_partition_owner }, 2046915dcf3SAlexander Graf }; 2056915dcf3SAlexander Graf 2066915dcf3SAlexander Graf static char *read_full_file(const char *filename, size_t *size) 2076915dcf3SAlexander Graf { 2086915dcf3SAlexander Graf char *buf, *bufp; 2096915dcf3SAlexander Graf struct stat sbuf; 2106915dcf3SAlexander Graf int len = 0, r, fd; 2116915dcf3SAlexander Graf 2126915dcf3SAlexander Graf fd = open(filename, O_RDONLY); 2136915dcf3SAlexander Graf if (fd < 0) 2146915dcf3SAlexander Graf return NULL; 2156915dcf3SAlexander Graf 2166915dcf3SAlexander Graf if (fstat(fd, &sbuf) < 0) 2176915dcf3SAlexander Graf return NULL; 2186915dcf3SAlexander Graf 2196915dcf3SAlexander Graf if (size) 2206915dcf3SAlexander Graf *size = sbuf.st_size; 2216915dcf3SAlexander Graf 2226915dcf3SAlexander Graf buf = malloc(sbuf.st_size); 2236915dcf3SAlexander Graf if (!buf) 2246915dcf3SAlexander Graf return NULL; 2256915dcf3SAlexander Graf 2266915dcf3SAlexander Graf bufp = buf; 2276915dcf3SAlexander Graf while (len < sbuf.st_size) { 2286915dcf3SAlexander Graf r = read(fd, bufp, sbuf.st_size - len); 2296915dcf3SAlexander Graf if (r < 0) 2306915dcf3SAlexander Graf return NULL; 2316915dcf3SAlexander Graf len += r; 2326915dcf3SAlexander Graf bufp += r; 2336915dcf3SAlexander Graf } 2346915dcf3SAlexander Graf 2356915dcf3SAlexander Graf close(fd); 2366915dcf3SAlexander Graf 2376915dcf3SAlexander Graf return buf; 2386915dcf3SAlexander Graf } 2396915dcf3SAlexander Graf 2406915dcf3SAlexander Graf static int bif_add_blob(const void *data, size_t len, size_t *offset) 2416915dcf3SAlexander Graf { 2426915dcf3SAlexander Graf size_t new_size; 2436915dcf3SAlexander Graf uintptr_t header_off; 2446915dcf3SAlexander Graf uintptr_t last_part_off; 2456915dcf3SAlexander Graf uintptr_t imgheader_off; 2466915dcf3SAlexander Graf uintptr_t old_data = (uintptr_t)bif_output.data; 2476915dcf3SAlexander Graf void *new_data; 2486915dcf3SAlexander Graf 2496915dcf3SAlexander Graf header_off = (uintptr_t)bif_output.header - old_data; 2506915dcf3SAlexander Graf last_part_off = (uintptr_t)bif_output.last_part - old_data; 2516915dcf3SAlexander Graf imgheader_off = (uintptr_t)bif_output.imgheader - old_data; 2526915dcf3SAlexander Graf 2536915dcf3SAlexander Graf if (offset && *offset) { 2546915dcf3SAlexander Graf /* Pad to a given offset */ 2556915dcf3SAlexander Graf if (bif_output.data_len > *offset) { 2566915dcf3SAlexander Graf printf("Can not pad to offset %zx\n", *offset); 2576915dcf3SAlexander Graf return -1; 2586915dcf3SAlexander Graf } 2596915dcf3SAlexander Graf 2606915dcf3SAlexander Graf bif_output.data_len = *offset; 2616915dcf3SAlexander Graf } 2626915dcf3SAlexander Graf 2636915dcf3SAlexander Graf new_size = ROUND(bif_output.data_len + len, 64); 2646915dcf3SAlexander Graf new_data = realloc(bif_output.data, new_size); 2656915dcf3SAlexander Graf memcpy(new_data + bif_output.data_len, data, len); 2666915dcf3SAlexander Graf if (offset) 2676915dcf3SAlexander Graf *offset = bif_output.data_len; 2686915dcf3SAlexander Graf bif_output.data = new_data; 2696915dcf3SAlexander Graf bif_output.data_len = new_size; 2706915dcf3SAlexander Graf 2716915dcf3SAlexander Graf /* Readjust internal pointers */ 2726915dcf3SAlexander Graf if (bif_output.header) 2736915dcf3SAlexander Graf bif_output.header = new_data + header_off; 2746915dcf3SAlexander Graf if (bif_output.last_part) 2756915dcf3SAlexander Graf bif_output.last_part = new_data + last_part_off; 2766915dcf3SAlexander Graf if (bif_output.imgheader) 2776915dcf3SAlexander Graf bif_output.imgheader = new_data + imgheader_off; 2786915dcf3SAlexander Graf 2796915dcf3SAlexander Graf return 0; 2806915dcf3SAlexander Graf } 2816915dcf3SAlexander Graf 2826915dcf3SAlexander Graf static int bif_init(void) 2836915dcf3SAlexander Graf { 2846915dcf3SAlexander Graf struct zynqmp_header header = { { 0 } }; 2856915dcf3SAlexander Graf int r; 2866915dcf3SAlexander Graf 2876915dcf3SAlexander Graf zynqmpimage_default_header(&header); 2886915dcf3SAlexander Graf 2896915dcf3SAlexander Graf r = bif_add_blob(&header, sizeof(header), NULL); 2906915dcf3SAlexander Graf if (r) 2916915dcf3SAlexander Graf return r; 2926915dcf3SAlexander Graf 2936915dcf3SAlexander Graf bif_output.header = (void *)bif_output.data; 2946915dcf3SAlexander Graf 2956915dcf3SAlexander Graf return 0; 2966915dcf3SAlexander Graf } 2976915dcf3SAlexander Graf 2986915dcf3SAlexander Graf static int bif_add_pmufw(struct bif_entry *bf, const char *data, size_t len) 2996915dcf3SAlexander Graf { 3006915dcf3SAlexander Graf int r; 3016915dcf3SAlexander Graf 3026915dcf3SAlexander Graf if (bif_output.header->image_offset) { 3036915dcf3SAlexander Graf printf("PMUFW expected before bootloader in your .bif file!\n"); 3046915dcf3SAlexander Graf return -1; 3056915dcf3SAlexander Graf } 3066915dcf3SAlexander Graf 3076915dcf3SAlexander Graf r = bif_add_blob(data, len, &bf->offset); 3086915dcf3SAlexander Graf if (r) 3096915dcf3SAlexander Graf return r; 3106915dcf3SAlexander Graf 3116915dcf3SAlexander Graf len = ROUND(len, 64); 3126915dcf3SAlexander Graf bif_output.header->pfw_image_length = cpu_to_le32(len); 3136915dcf3SAlexander Graf bif_output.header->total_pfw_image_length = cpu_to_le32(len); 3146915dcf3SAlexander Graf bif_output.header->image_offset = cpu_to_le32(bf->offset); 3156915dcf3SAlexander Graf 3166915dcf3SAlexander Graf return 0; 3176915dcf3SAlexander Graf } 3186915dcf3SAlexander Graf 3196915dcf3SAlexander Graf static int bif_add_part(struct bif_entry *bf, const char *data, size_t len) 3206915dcf3SAlexander Graf { 3216915dcf3SAlexander Graf size_t parthdr_offset = 0; 32216c78cbaSMichael Tretter size_t len_padded = ROUND(len, 4); 32316c78cbaSMichael Tretter 3246915dcf3SAlexander Graf struct partition_header parthdr = { 32516c78cbaSMichael Tretter .len_enc = cpu_to_le32(len_padded / 4), 32616c78cbaSMichael Tretter .len_unenc = cpu_to_le32(len_padded / 4), 32716c78cbaSMichael Tretter .len = cpu_to_le32(len_padded / 4), 3286915dcf3SAlexander Graf .entry_point = cpu_to_le64(bf->entry), 3296915dcf3SAlexander Graf .load_address = cpu_to_le64(bf->load), 3306915dcf3SAlexander Graf }; 3316915dcf3SAlexander Graf int r; 3326915dcf3SAlexander Graf uint32_t csum; 3336915dcf3SAlexander Graf 33416c78cbaSMichael Tretter if (len < len_padded) { 33516c78cbaSMichael Tretter char *newdata = malloc(len_padded); 33616c78cbaSMichael Tretter memcpy(newdata, data, len); 33716c78cbaSMichael Tretter memset(newdata + len, 0, len_padded - len); 33816c78cbaSMichael Tretter data = newdata; 33916c78cbaSMichael Tretter } 34016c78cbaSMichael Tretter 3416915dcf3SAlexander Graf if (bf->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE)) 3426915dcf3SAlexander Graf return bif_add_pmufw(bf, data, len); 3436915dcf3SAlexander Graf 3446915dcf3SAlexander Graf r = bif_add_blob(data, len, &bf->offset); 3456915dcf3SAlexander Graf if (r) 3466915dcf3SAlexander Graf return r; 3476915dcf3SAlexander Graf 3486915dcf3SAlexander Graf parthdr.offset = cpu_to_le32(bf->offset / 4); 3496915dcf3SAlexander Graf 3506915dcf3SAlexander Graf if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) { 3516915dcf3SAlexander Graf if (bif_output.last_part) { 3526915dcf3SAlexander Graf printf("ERROR: Bootloader expected before others\n"); 3536915dcf3SAlexander Graf return -1; 3546915dcf3SAlexander Graf } 3556915dcf3SAlexander Graf 3566915dcf3SAlexander Graf parthdr.offset = cpu_to_le32(bif_output.header->image_offset); 3576915dcf3SAlexander Graf parthdr.len = cpu_to_le32((bf->offset + len - 3586915dcf3SAlexander Graf bif_output.header->image_offset) / 4); 3596915dcf3SAlexander Graf parthdr.len_enc = parthdr.len; 3606915dcf3SAlexander Graf parthdr.len_unenc = parthdr.len; 3616915dcf3SAlexander Graf } 3626915dcf3SAlexander Graf 3636915dcf3SAlexander Graf /* Normalize EL */ 3646915dcf3SAlexander Graf bf->exp_lvl = bf->exp_lvl ? bf->exp_lvl - 1 : 3; 3656915dcf3SAlexander Graf parthdr.attributes |= bf->exp_lvl << PART_ATTR_TARGET_EL_SHIFT; 3666915dcf3SAlexander Graf parthdr.attributes |= bf->dest_dev; 3676915dcf3SAlexander Graf parthdr.attributes |= bf->dest_cpu; 3686915dcf3SAlexander Graf if (bf->flags & (1ULL << BIF_FLAG_TZ)) 3696915dcf3SAlexander Graf parthdr.attributes |= PART_ATTR_TZ_SECURE; 3706915dcf3SAlexander Graf if (bf->flags & (1ULL << BIF_FLAG_PART_OWNER_UBOOT)) 3716915dcf3SAlexander Graf parthdr.attributes |= PART_ATTR_PART_OWNER_UBOOT; 3726915dcf3SAlexander Graf switch (bf->dest_cpu) { 3736915dcf3SAlexander Graf case PART_ATTR_DEST_CPU_NONE: 3746915dcf3SAlexander Graf case PART_ATTR_DEST_CPU_A53_0: 3756915dcf3SAlexander Graf case PART_ATTR_DEST_CPU_A53_1: 3766915dcf3SAlexander Graf case PART_ATTR_DEST_CPU_A53_2: 3776915dcf3SAlexander Graf case PART_ATTR_DEST_CPU_A53_3: 3786915dcf3SAlexander Graf if (bf->flags & (1ULL << BIF_FLAG_AARCH32)) 3796915dcf3SAlexander Graf parthdr.attributes |= PART_ATTR_A53_EXEC_AARCH32; 3806915dcf3SAlexander Graf } 3816915dcf3SAlexander Graf 3826915dcf3SAlexander Graf csum = zynqmp_csum(&parthdr, &parthdr.checksum); 3836915dcf3SAlexander Graf parthdr.checksum = cpu_to_le32(csum); 3846915dcf3SAlexander Graf 3856915dcf3SAlexander Graf r = bif_add_blob(&parthdr, sizeof(parthdr), &parthdr_offset); 3866915dcf3SAlexander Graf if (r) 3876915dcf3SAlexander Graf return r; 3886915dcf3SAlexander Graf 3896915dcf3SAlexander Graf /* Add image header table if not there yet */ 3906915dcf3SAlexander Graf if (!bif_output.imgheader) { 3916915dcf3SAlexander Graf size_t imghdr_off = 0; 3926915dcf3SAlexander Graf struct image_header_table imghdr = { 3936915dcf3SAlexander Graf .version = cpu_to_le32(0x01020000), 3946915dcf3SAlexander Graf .nr_parts = 0, 3956915dcf3SAlexander Graf }; 3966915dcf3SAlexander Graf 3976915dcf3SAlexander Graf r = bif_add_blob(&imghdr, sizeof(imghdr), &imghdr_off); 3986915dcf3SAlexander Graf if (r) 3996915dcf3SAlexander Graf return r; 4006915dcf3SAlexander Graf 4016915dcf3SAlexander Graf bif_output.header->image_header_table_offset = imghdr_off; 4026915dcf3SAlexander Graf bif_output.imgheader = (void *)(bif_output.data + imghdr_off); 4036915dcf3SAlexander Graf } 4046915dcf3SAlexander Graf 4056915dcf3SAlexander Graf bif_output.imgheader->nr_parts = cpu_to_le32(le32_to_cpu( 4066915dcf3SAlexander Graf bif_output.imgheader->nr_parts) + 1); 4076915dcf3SAlexander Graf 4086915dcf3SAlexander Graf /* Link to this partition header */ 4096915dcf3SAlexander Graf if (bif_output.last_part) { 4106915dcf3SAlexander Graf bif_output.last_part->next_partition_offset = 4116915dcf3SAlexander Graf cpu_to_le32(parthdr_offset / 4); 4126915dcf3SAlexander Graf 4136915dcf3SAlexander Graf /* Recalc checksum of last_part */ 4146915dcf3SAlexander Graf csum = zynqmp_csum(bif_output.last_part, 4156915dcf3SAlexander Graf &bif_output.last_part->checksum); 4166915dcf3SAlexander Graf bif_output.last_part->checksum = cpu_to_le32(csum); 4176915dcf3SAlexander Graf } else { 4186915dcf3SAlexander Graf bif_output.imgheader->partition_header_offset = 4196915dcf3SAlexander Graf cpu_to_le32(parthdr_offset / 4); 4206915dcf3SAlexander Graf } 4216915dcf3SAlexander Graf bif_output.last_part = (void *)(bif_output.data + parthdr_offset); 4226915dcf3SAlexander Graf 4236915dcf3SAlexander Graf if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) { 4246915dcf3SAlexander Graf bif_output.header->image_load = cpu_to_le32(bf->load); 4256915dcf3SAlexander Graf if (!bif_output.header->image_offset) 4266915dcf3SAlexander Graf bif_output.header->image_offset = 4276915dcf3SAlexander Graf cpu_to_le32(bf->offset); 428*775ed87aSMichal Simek bif_output.header->image_size = cpu_to_le32(len_padded); 429*775ed87aSMichal Simek bif_output.header->image_stored_size = cpu_to_le32(len_padded); 4306915dcf3SAlexander Graf 4316915dcf3SAlexander Graf bif_output.header->image_attributes &= ~HEADER_CPU_SELECT_MASK; 4326915dcf3SAlexander Graf switch (bf->dest_cpu) { 4336915dcf3SAlexander Graf default: 4346915dcf3SAlexander Graf case PART_ATTR_DEST_CPU_A53_0: 4356915dcf3SAlexander Graf if (bf->flags & BIF_FLAG_AARCH32) 4366915dcf3SAlexander Graf bif_output.header->image_attributes |= 4376915dcf3SAlexander Graf HEADER_CPU_SELECT_A53_32BIT; 4386915dcf3SAlexander Graf else 4396915dcf3SAlexander Graf bif_output.header->image_attributes |= 4406915dcf3SAlexander Graf HEADER_CPU_SELECT_A53_64BIT; 4416915dcf3SAlexander Graf break; 4426915dcf3SAlexander Graf case PART_ATTR_DEST_CPU_R5_0: 4436915dcf3SAlexander Graf bif_output.header->image_attributes |= 4446915dcf3SAlexander Graf HEADER_CPU_SELECT_R5_SINGLE; 4456915dcf3SAlexander Graf break; 4466915dcf3SAlexander Graf case PART_ATTR_DEST_CPU_R5_L: 4476915dcf3SAlexander Graf bif_output.header->image_attributes |= 4486915dcf3SAlexander Graf HEADER_CPU_SELECT_R5_DUAL; 4496915dcf3SAlexander Graf break; 4506915dcf3SAlexander Graf } 4516915dcf3SAlexander Graf } 4526915dcf3SAlexander Graf 4536915dcf3SAlexander Graf return 0; 4546915dcf3SAlexander Graf } 4556915dcf3SAlexander Graf 4566915dcf3SAlexander Graf /* Add .bit bitstream */ 4576915dcf3SAlexander Graf static int bif_add_bit(struct bif_entry *bf) 4586915dcf3SAlexander Graf { 4596915dcf3SAlexander Graf char *bit = read_full_file(bf->filename, NULL); 4606915dcf3SAlexander Graf char *bitbin; 4616915dcf3SAlexander Graf uint8_t initial_header[] = { 0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f, 4626915dcf3SAlexander Graf 0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01, 0x61 }; 4636915dcf3SAlexander Graf uint16_t len; 4646915dcf3SAlexander Graf uint32_t bitlen; 4656915dcf3SAlexander Graf int i; 4666915dcf3SAlexander Graf 4676915dcf3SAlexander Graf if (!bit) 4686915dcf3SAlexander Graf return -1; 4696915dcf3SAlexander Graf 4706915dcf3SAlexander Graf /* Skip initial header */ 4716915dcf3SAlexander Graf if (memcmp(bit, initial_header, sizeof(initial_header))) 4726915dcf3SAlexander Graf return -1; 4736915dcf3SAlexander Graf 4746915dcf3SAlexander Graf bit += sizeof(initial_header); 4756915dcf3SAlexander Graf 4766915dcf3SAlexander Graf /* Design name */ 4776915dcf3SAlexander Graf len = be16_to_cpu(*(uint16_t *)bit); 4786915dcf3SAlexander Graf bit += sizeof(uint16_t); 4796915dcf3SAlexander Graf debug("Design: %s\n", bit); 4806915dcf3SAlexander Graf bit += len; 4816915dcf3SAlexander Graf 4826915dcf3SAlexander Graf /* Device identifier */ 4836915dcf3SAlexander Graf if (*bit != 'b') 4846915dcf3SAlexander Graf return -1; 4856915dcf3SAlexander Graf bit++; 4866915dcf3SAlexander Graf len = be16_to_cpu(*(uint16_t *)bit); 4876915dcf3SAlexander Graf bit += sizeof(uint16_t); 4886915dcf3SAlexander Graf debug("Device: %s\n", bit); 4896915dcf3SAlexander Graf bit += len; 4906915dcf3SAlexander Graf 4916915dcf3SAlexander Graf /* Date */ 4926915dcf3SAlexander Graf if (*bit != 'c') 4936915dcf3SAlexander Graf return -1; 4946915dcf3SAlexander Graf bit++; 4956915dcf3SAlexander Graf len = be16_to_cpu(*(uint16_t *)bit); 4966915dcf3SAlexander Graf bit += sizeof(uint16_t); 4976915dcf3SAlexander Graf debug("Date: %s\n", bit); 4986915dcf3SAlexander Graf bit += len; 4996915dcf3SAlexander Graf 5006915dcf3SAlexander Graf /* Time */ 5016915dcf3SAlexander Graf if (*bit != 'd') 5026915dcf3SAlexander Graf return -1; 5036915dcf3SAlexander Graf bit++; 5046915dcf3SAlexander Graf len = be16_to_cpu(*(uint16_t *)bit); 5056915dcf3SAlexander Graf bit += sizeof(uint16_t); 5066915dcf3SAlexander Graf debug("Time: %s\n", bit); 5076915dcf3SAlexander Graf bit += len; 5086915dcf3SAlexander Graf 5096915dcf3SAlexander Graf /* Bitstream length */ 5106915dcf3SAlexander Graf if (*bit != 'e') 5116915dcf3SAlexander Graf return -1; 5126915dcf3SAlexander Graf bit++; 5136915dcf3SAlexander Graf bitlen = be32_to_cpu(*(uint32_t *)bit); 5146915dcf3SAlexander Graf bit += sizeof(uint32_t); 5156915dcf3SAlexander Graf bitbin = bit; 5166915dcf3SAlexander Graf 5176915dcf3SAlexander Graf debug("Bitstream Length: 0x%x\n", bitlen); 5186915dcf3SAlexander Graf for (i = 0; i < bitlen; i += sizeof(uint32_t)) { 5196915dcf3SAlexander Graf uint32_t *bitbin32 = (uint32_t *)&bitbin[i]; 5206915dcf3SAlexander Graf *bitbin32 = __swab32(*bitbin32); 5216915dcf3SAlexander Graf } 5226915dcf3SAlexander Graf 5236915dcf3SAlexander Graf if (!bf->dest_dev) 5246915dcf3SAlexander Graf bf->dest_dev = PART_ATTR_DEST_DEVICE_PL; 5256915dcf3SAlexander Graf 5266915dcf3SAlexander Graf bf->load = 0xffffffff; 5276915dcf3SAlexander Graf bf->entry = 0; 5286915dcf3SAlexander Graf 5296915dcf3SAlexander Graf bf->flags |= 1ULL << BIF_FLAG_BIT_FILE; 5306915dcf3SAlexander Graf return bif_add_part(bf, bit, bitlen); 5316915dcf3SAlexander Graf } 5326915dcf3SAlexander Graf 5336915dcf3SAlexander Graf /* Add .bin bitstream */ 5346915dcf3SAlexander Graf static int bif_add_bin(struct bif_entry *bf) 5356915dcf3SAlexander Graf { 5366915dcf3SAlexander Graf size_t size; 5376915dcf3SAlexander Graf char *bin = read_full_file(bf->filename, &size); 5386915dcf3SAlexander Graf 5396915dcf3SAlexander Graf if (!bf->dest_dev) 5406915dcf3SAlexander Graf bf->dest_dev = PART_ATTR_DEST_DEVICE_PS; 5416915dcf3SAlexander Graf 5426915dcf3SAlexander Graf bf->flags |= 1ULL << BIF_FLAG_BIN_FILE; 5436915dcf3SAlexander Graf return bif_add_part(bf, bin, size); 5446915dcf3SAlexander Graf } 5456915dcf3SAlexander Graf 5466915dcf3SAlexander Graf /* Add elf file */ 5476915dcf3SAlexander Graf static char *elf2flat64(char *elf, size_t *flat_size, size_t *load_addr) 5486915dcf3SAlexander Graf { 5496915dcf3SAlexander Graf Elf64_Ehdr *ehdr; 5506915dcf3SAlexander Graf Elf64_Shdr *shdr; 5516915dcf3SAlexander Graf size_t min_addr = -1, max_addr = 0; 5526915dcf3SAlexander Graf char *flat; 5536915dcf3SAlexander Graf int i; 5546915dcf3SAlexander Graf 5556915dcf3SAlexander Graf ehdr = (void *)elf; 5566915dcf3SAlexander Graf shdr = (void *)(elf + le64_to_cpu(ehdr->e_shoff)); 5576915dcf3SAlexander Graf 5586915dcf3SAlexander Graf /* Look for smallest / biggest address */ 5596915dcf3SAlexander Graf for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++, shdr++) { 5606915dcf3SAlexander Graf if (!shdr->sh_size || !shdr->sh_addr || 5616915dcf3SAlexander Graf !(shdr->sh_flags & SHF_ALLOC) || 5626915dcf3SAlexander Graf (shdr->sh_type == SHT_NOBITS)) 5636915dcf3SAlexander Graf continue; 5646915dcf3SAlexander Graf 5656915dcf3SAlexander Graf if (le64_to_cpu(shdr->sh_addr) < min_addr) 5666915dcf3SAlexander Graf min_addr = le64_to_cpu(shdr->sh_addr); 5676915dcf3SAlexander Graf if ((le64_to_cpu(shdr->sh_addr) + le64_to_cpu(shdr->sh_size)) > 5686915dcf3SAlexander Graf max_addr) 5696915dcf3SAlexander Graf max_addr = le64_to_cpu(shdr->sh_addr) + 5706915dcf3SAlexander Graf le64_to_cpu(shdr->sh_size); 5716915dcf3SAlexander Graf } 5726915dcf3SAlexander Graf 5736915dcf3SAlexander Graf *load_addr = min_addr; 5746915dcf3SAlexander Graf *flat_size = max_addr - min_addr; 5756915dcf3SAlexander Graf flat = calloc(1, *flat_size); 5766915dcf3SAlexander Graf if (!flat) 5776915dcf3SAlexander Graf return NULL; 5786915dcf3SAlexander Graf 5796915dcf3SAlexander Graf shdr = (void *)(elf + le64_to_cpu(ehdr->e_shoff)); 5806915dcf3SAlexander Graf for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++, shdr++) { 5816915dcf3SAlexander Graf char *dst = flat + le64_to_cpu(shdr->sh_addr) - min_addr; 5826915dcf3SAlexander Graf char *src = elf + le64_to_cpu(shdr->sh_offset); 5836915dcf3SAlexander Graf 5846915dcf3SAlexander Graf if (!shdr->sh_size || !shdr->sh_addr || 5856915dcf3SAlexander Graf !(shdr->sh_flags & SHF_ALLOC)) 5866915dcf3SAlexander Graf continue; 5876915dcf3SAlexander Graf 5886915dcf3SAlexander Graf if (shdr->sh_type != SHT_NOBITS) 5896915dcf3SAlexander Graf memcpy(dst, src, le64_to_cpu(shdr->sh_size)); 5906915dcf3SAlexander Graf } 5916915dcf3SAlexander Graf 5926915dcf3SAlexander Graf return flat; 5936915dcf3SAlexander Graf } 5946915dcf3SAlexander Graf 5956915dcf3SAlexander Graf static char *elf2flat32(char *elf, size_t *flat_size, size_t *load_addr) 5966915dcf3SAlexander Graf { 5976915dcf3SAlexander Graf Elf32_Ehdr *ehdr; 5986915dcf3SAlexander Graf Elf32_Shdr *shdr; 5996915dcf3SAlexander Graf size_t min_addr = -1, max_addr = 0; 6006915dcf3SAlexander Graf char *flat; 6016915dcf3SAlexander Graf int i; 6026915dcf3SAlexander Graf 6036915dcf3SAlexander Graf ehdr = (void *)elf; 6046915dcf3SAlexander Graf shdr = (void *)(elf + le32_to_cpu(ehdr->e_shoff)); 6056915dcf3SAlexander Graf 6066915dcf3SAlexander Graf /* Look for smallest / biggest address */ 6076915dcf3SAlexander Graf for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++, shdr++) { 6086915dcf3SAlexander Graf if (!shdr->sh_size || !shdr->sh_addr || 6096915dcf3SAlexander Graf !(shdr->sh_flags & SHF_ALLOC) || 6106915dcf3SAlexander Graf (shdr->sh_type == SHT_NOBITS)) 6116915dcf3SAlexander Graf continue; 6126915dcf3SAlexander Graf 6136915dcf3SAlexander Graf if (le32_to_cpu(shdr->sh_addr) < min_addr) 6146915dcf3SAlexander Graf min_addr = le32_to_cpu(shdr->sh_addr); 6156915dcf3SAlexander Graf if ((le32_to_cpu(shdr->sh_addr) + le32_to_cpu(shdr->sh_size)) > 6166915dcf3SAlexander Graf max_addr) 6176915dcf3SAlexander Graf max_addr = le32_to_cpu(shdr->sh_addr) + 6186915dcf3SAlexander Graf le32_to_cpu(shdr->sh_size); 6196915dcf3SAlexander Graf } 6206915dcf3SAlexander Graf 6216915dcf3SAlexander Graf *load_addr = min_addr; 6226915dcf3SAlexander Graf *flat_size = max_addr - min_addr; 6236915dcf3SAlexander Graf flat = calloc(1, *flat_size); 6246915dcf3SAlexander Graf if (!flat) 6256915dcf3SAlexander Graf return NULL; 6266915dcf3SAlexander Graf 6276915dcf3SAlexander Graf shdr = (void *)(elf + le32_to_cpu(ehdr->e_shoff)); 6286915dcf3SAlexander Graf for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++, shdr++) { 6296915dcf3SAlexander Graf char *dst = flat + le32_to_cpu(shdr->sh_addr) - min_addr; 6306915dcf3SAlexander Graf char *src = elf + le32_to_cpu(shdr->sh_offset); 6316915dcf3SAlexander Graf 6326915dcf3SAlexander Graf if (!shdr->sh_size || !shdr->sh_addr || 6336915dcf3SAlexander Graf !(shdr->sh_flags & SHF_ALLOC)) 6346915dcf3SAlexander Graf continue; 6356915dcf3SAlexander Graf 6366915dcf3SAlexander Graf if (shdr->sh_type != SHT_NOBITS) 6376915dcf3SAlexander Graf memcpy(dst, src, le32_to_cpu(shdr->sh_size)); 6386915dcf3SAlexander Graf } 6396915dcf3SAlexander Graf 6406915dcf3SAlexander Graf return flat; 6416915dcf3SAlexander Graf } 6426915dcf3SAlexander Graf 6436915dcf3SAlexander Graf static int bif_add_elf(struct bif_entry *bf) 6446915dcf3SAlexander Graf { 6456915dcf3SAlexander Graf size_t size; 6466915dcf3SAlexander Graf size_t elf_size; 6476915dcf3SAlexander Graf char *elf; 6486915dcf3SAlexander Graf char *flat; 6496915dcf3SAlexander Graf size_t load_addr; 6506915dcf3SAlexander Graf Elf32_Ehdr *ehdr32; 6516915dcf3SAlexander Graf Elf64_Ehdr *ehdr64; 6526915dcf3SAlexander Graf 6536915dcf3SAlexander Graf elf = read_full_file(bf->filename, &elf_size); 6546915dcf3SAlexander Graf if (!elf) 6556915dcf3SAlexander Graf return -1; 6566915dcf3SAlexander Graf 6576915dcf3SAlexander Graf ehdr32 = (void *)elf; 6586915dcf3SAlexander Graf ehdr64 = (void *)elf; 6596915dcf3SAlexander Graf 6606915dcf3SAlexander Graf switch (ehdr32->e_ident[EI_CLASS]) { 6616915dcf3SAlexander Graf case ELFCLASS32: 6626915dcf3SAlexander Graf flat = elf2flat32(elf, &size, &load_addr); 6636915dcf3SAlexander Graf bf->entry = le32_to_cpu(ehdr32->e_entry); 6646915dcf3SAlexander Graf bf->flags |= 1ULL << BIF_FLAG_AARCH32; 6656915dcf3SAlexander Graf break; 6666915dcf3SAlexander Graf case ELFCLASS64: 6676915dcf3SAlexander Graf flat = elf2flat64(elf, &size, &load_addr); 6686915dcf3SAlexander Graf bf->entry = le64_to_cpu(ehdr64->e_entry); 6696915dcf3SAlexander Graf break; 6706915dcf3SAlexander Graf default: 6716915dcf3SAlexander Graf printf("Unknown ELF class: %d\n", ehdr32->e_ident[EI_CLASS]); 6726915dcf3SAlexander Graf return -1; 6736915dcf3SAlexander Graf } 6746915dcf3SAlexander Graf 6756915dcf3SAlexander Graf if (!flat) 6766915dcf3SAlexander Graf return -1; 6776915dcf3SAlexander Graf 6786915dcf3SAlexander Graf bf->load = load_addr; 6796915dcf3SAlexander Graf if (!bf->dest_dev) 6806915dcf3SAlexander Graf bf->dest_dev = PART_ATTR_DEST_DEVICE_PS; 6816915dcf3SAlexander Graf 6826915dcf3SAlexander Graf bf->flags |= 1ULL << BIF_FLAG_ELF_FILE; 6836915dcf3SAlexander Graf return bif_add_part(bf, flat, size); 6846915dcf3SAlexander Graf } 6856915dcf3SAlexander Graf 6866915dcf3SAlexander Graf static const struct bif_file_type bif_file_types[] = { 6876915dcf3SAlexander Graf { 6886915dcf3SAlexander Graf .name = "bitstream (.bit)", 6896915dcf3SAlexander Graf .header = 0x00090ff0, 6906915dcf3SAlexander Graf .add = bif_add_bit, 6916915dcf3SAlexander Graf }, 6926915dcf3SAlexander Graf 6936915dcf3SAlexander Graf { 6946915dcf3SAlexander Graf .name = "ELF", 6956915dcf3SAlexander Graf .header = 0x7f454c46, 6966915dcf3SAlexander Graf .add = bif_add_elf, 6976915dcf3SAlexander Graf }, 6986915dcf3SAlexander Graf 6996915dcf3SAlexander Graf /* Anything else is a .bin file */ 7006915dcf3SAlexander Graf { 7016915dcf3SAlexander Graf .name = ".bin", 7026915dcf3SAlexander Graf .add = bif_add_bin, 7036915dcf3SAlexander Graf }, 7046915dcf3SAlexander Graf }; 7056915dcf3SAlexander Graf 7066915dcf3SAlexander Graf static int bif_fsbl_config(struct bif_entry *fsbl_config, 7076915dcf3SAlexander Graf struct bif_entry *entries, int nr_entries) 7086915dcf3SAlexander Graf { 7096915dcf3SAlexander Graf int i; 7106915dcf3SAlexander Graf int config_set = 0; 7116915dcf3SAlexander Graf struct { 7126915dcf3SAlexander Graf const char *name; 7136915dcf3SAlexander Graf uint64_t flags; 7146915dcf3SAlexander Graf uint64_t dest_cpu; 7156915dcf3SAlexander Graf } configs[] = { 7166915dcf3SAlexander Graf { .name = "a5x_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 }, 7176915dcf3SAlexander Graf { .name = "a53_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 }, 7186915dcf3SAlexander Graf { .name = "a5x_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0, 7196915dcf3SAlexander Graf .flags = 1ULL << BIF_FLAG_AARCH32 }, 7206915dcf3SAlexander Graf { .name = "a53_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0, 7216915dcf3SAlexander Graf .flags = 1ULL << BIF_FLAG_AARCH32 }, 7226915dcf3SAlexander Graf { .name = "r5_single", .dest_cpu = PART_ATTR_DEST_CPU_R5_0 }, 7236915dcf3SAlexander Graf { .name = "r5_dual", .dest_cpu = PART_ATTR_DEST_CPU_R5_L }, 7246915dcf3SAlexander Graf }; 7256915dcf3SAlexander Graf 7266915dcf3SAlexander Graf /* Set target CPU of bootloader entry */ 7276915dcf3SAlexander Graf for (i = 0; i < nr_entries; i++) { 7286915dcf3SAlexander Graf struct bif_entry *b = &entries[i]; 7296915dcf3SAlexander Graf const char *config_attr = fsbl_config->filename; 7306915dcf3SAlexander Graf int j; 7316915dcf3SAlexander Graf 7326915dcf3SAlexander Graf if (!(b->flags & (1ULL << BIF_FLAG_BOOTLOADER))) 7336915dcf3SAlexander Graf continue; 7346915dcf3SAlexander Graf 7356915dcf3SAlexander Graf for (j = 0; j < ARRAY_SIZE(configs); j++) { 7366915dcf3SAlexander Graf if (!strncmp(config_attr, configs[j].name, 7376915dcf3SAlexander Graf strlen(configs[j].name))) { 7386915dcf3SAlexander Graf b->dest_cpu = configs[j].dest_cpu; 7396915dcf3SAlexander Graf b->flags |= configs[j].flags; 7406915dcf3SAlexander Graf config_set = 1; 7416915dcf3SAlexander Graf } 7426915dcf3SAlexander Graf } 7436915dcf3SAlexander Graf 7446915dcf3SAlexander Graf if (!config_set) { 7456915dcf3SAlexander Graf printf("ERROR: Unsupported fsbl_config: %s\n", 7466915dcf3SAlexander Graf config_attr); 7476915dcf3SAlexander Graf return -1; 7486915dcf3SAlexander Graf } 7496915dcf3SAlexander Graf } 7506915dcf3SAlexander Graf 7516915dcf3SAlexander Graf if (!config_set) { 7526915dcf3SAlexander Graf printf("ERROR: fsbl_config w/o bootloader\n"); 7536915dcf3SAlexander Graf return -1; 7546915dcf3SAlexander Graf } 7556915dcf3SAlexander Graf 7566915dcf3SAlexander Graf return 0; 7576915dcf3SAlexander Graf } 7586915dcf3SAlexander Graf 7596915dcf3SAlexander Graf static const struct bif_flags *find_flag(char *str) 7606915dcf3SAlexander Graf { 7616915dcf3SAlexander Graf const struct bif_flags *bf; 7626915dcf3SAlexander Graf int i; 7636915dcf3SAlexander Graf 7646915dcf3SAlexander Graf for (i = 0; i < ARRAY_SIZE(bif_flags); i++) { 7656915dcf3SAlexander Graf bf = &bif_flags[i]; 7666915dcf3SAlexander Graf if (!strncmp(bf->name, str, strlen(bf->name))) 7676915dcf3SAlexander Graf return bf; 7686915dcf3SAlexander Graf } 7696915dcf3SAlexander Graf 7706915dcf3SAlexander Graf printf("ERROR: Flag '%s' not found\n", str); 7716915dcf3SAlexander Graf 7726915dcf3SAlexander Graf return NULL; 7736915dcf3SAlexander Graf } 7746915dcf3SAlexander Graf 7756915dcf3SAlexander Graf static int bif_open_file(struct bif_entry *entry) 7766915dcf3SAlexander Graf { 7776915dcf3SAlexander Graf int fd = open(entry->filename, O_RDONLY); 7786915dcf3SAlexander Graf 7796915dcf3SAlexander Graf if (fd < 0) 7806915dcf3SAlexander Graf printf("Error opening file %s\n", entry->filename); 7816915dcf3SAlexander Graf 7826915dcf3SAlexander Graf return fd; 7836915dcf3SAlexander Graf } 7846915dcf3SAlexander Graf 7856915dcf3SAlexander Graf static const struct bif_file_type *get_file_type(struct bif_entry *entry) 7866915dcf3SAlexander Graf { 7876915dcf3SAlexander Graf int fd = bif_open_file(entry); 7886915dcf3SAlexander Graf uint32_t header; 7896915dcf3SAlexander Graf int i; 7906915dcf3SAlexander Graf 7916915dcf3SAlexander Graf if (fd < 0) 7926915dcf3SAlexander Graf return NULL; 7936915dcf3SAlexander Graf 7946915dcf3SAlexander Graf if (read(fd, &header, sizeof(header)) != sizeof(header)) { 7956915dcf3SAlexander Graf printf("Error reading file %s", entry->filename); 7966915dcf3SAlexander Graf return NULL; 7976915dcf3SAlexander Graf } 7986915dcf3SAlexander Graf 7996915dcf3SAlexander Graf close(fd); 8006915dcf3SAlexander Graf 8016915dcf3SAlexander Graf for (i = 0; i < ARRAY_SIZE(bif_file_types); i++) { 8026915dcf3SAlexander Graf const struct bif_file_type *type = &bif_file_types[i]; 8036915dcf3SAlexander Graf 8046915dcf3SAlexander Graf if (!type->header) 8056915dcf3SAlexander Graf return type; 8066915dcf3SAlexander Graf if (type->header == be32_to_cpu(header)) 8076915dcf3SAlexander Graf return type; 8086915dcf3SAlexander Graf } 8096915dcf3SAlexander Graf 8106915dcf3SAlexander Graf return NULL; 8116915dcf3SAlexander Graf } 8126915dcf3SAlexander Graf 8136915dcf3SAlexander Graf #define NEXT_CHAR(str, chr) ({ \ 8146915dcf3SAlexander Graf char *_n = strchr(str, chr); \ 8156915dcf3SAlexander Graf if (!_n) \ 8166915dcf3SAlexander Graf goto err; \ 8176915dcf3SAlexander Graf _n; \ 8186915dcf3SAlexander Graf }) 8196915dcf3SAlexander Graf 8206915dcf3SAlexander Graf static char *skip_whitespace(char *str) 8216915dcf3SAlexander Graf { 8226915dcf3SAlexander Graf while (*str == ' ' || *str == '\t') 8236915dcf3SAlexander Graf str++; 8246915dcf3SAlexander Graf 8256915dcf3SAlexander Graf return str; 8266915dcf3SAlexander Graf } 8276915dcf3SAlexander Graf 8286915dcf3SAlexander Graf int zynqmpbif_copy_image(int outfd, struct image_tool_params *mparams) 8296915dcf3SAlexander Graf { 8306915dcf3SAlexander Graf char *bif, *bifp, *bifpn; 8316915dcf3SAlexander Graf char *line; 8326915dcf3SAlexander Graf struct bif_entry entries[32] = { { 0 } }; 8336915dcf3SAlexander Graf int nr_entries = 0; 8346915dcf3SAlexander Graf struct bif_entry *entry = entries; 8356915dcf3SAlexander Graf size_t len; 8366915dcf3SAlexander Graf int i; 8376915dcf3SAlexander Graf uint32_t csum; 8386915dcf3SAlexander Graf int bldr = -1; 8396915dcf3SAlexander Graf 8406915dcf3SAlexander Graf bif_init(); 8416915dcf3SAlexander Graf 8426915dcf3SAlexander Graf /* Read .bif input file */ 8436915dcf3SAlexander Graf bif = read_full_file(mparams->datafile, NULL); 8446915dcf3SAlexander Graf if (!bif) 8456915dcf3SAlexander Graf goto err; 8466915dcf3SAlexander Graf 8476915dcf3SAlexander Graf /* Interpret .bif file */ 8486915dcf3SAlexander Graf bifp = bif; 8496915dcf3SAlexander Graf 8506915dcf3SAlexander Graf /* A bif description starts with a { section */ 8516915dcf3SAlexander Graf bifp = NEXT_CHAR(bifp, '{') + 1; 8526915dcf3SAlexander Graf 8536915dcf3SAlexander Graf /* Read every line */ 8546915dcf3SAlexander Graf while (1) { 8556915dcf3SAlexander Graf bifpn = NEXT_CHAR(bifp, '\n'); 8566915dcf3SAlexander Graf 8576915dcf3SAlexander Graf if (bifpn[-1] == '\r') 8586915dcf3SAlexander Graf bifpn[-1] = '\0'; 8596915dcf3SAlexander Graf 8606915dcf3SAlexander Graf *bifpn = '\0'; 8616915dcf3SAlexander Graf bifpn++; 8626915dcf3SAlexander Graf line = bifp; 8636915dcf3SAlexander Graf 8646915dcf3SAlexander Graf line = skip_whitespace(line); 8656915dcf3SAlexander Graf 8666915dcf3SAlexander Graf /* Attributes? */ 8676915dcf3SAlexander Graf if (*line == '[') { 8686915dcf3SAlexander Graf line++; 8696915dcf3SAlexander Graf while (1) { 8706915dcf3SAlexander Graf const struct bif_flags *bf; 8716915dcf3SAlexander Graf 8726915dcf3SAlexander Graf line = skip_whitespace(line); 8736915dcf3SAlexander Graf bf = find_flag(line); 8746915dcf3SAlexander Graf if (!bf) 8756915dcf3SAlexander Graf goto err; 8766915dcf3SAlexander Graf 8776915dcf3SAlexander Graf line += strlen(bf->name); 8786915dcf3SAlexander Graf if (bf->parse) 8796915dcf3SAlexander Graf line = bf->parse(line, entry); 8806915dcf3SAlexander Graf else 8816915dcf3SAlexander Graf entry->flags |= 1ULL << bf->flag; 8826915dcf3SAlexander Graf 8836915dcf3SAlexander Graf if (!line) 8846915dcf3SAlexander Graf goto err; 8856915dcf3SAlexander Graf 8866915dcf3SAlexander Graf /* Go to next attribute or quit */ 8876915dcf3SAlexander Graf if (*line == ']') { 8886915dcf3SAlexander Graf line++; 8896915dcf3SAlexander Graf break; 8906915dcf3SAlexander Graf } 8916915dcf3SAlexander Graf if (*line == ',') 8926915dcf3SAlexander Graf line++; 8936915dcf3SAlexander Graf } 8946915dcf3SAlexander Graf } 8956915dcf3SAlexander Graf 8966915dcf3SAlexander Graf /* End of image description */ 8976915dcf3SAlexander Graf if (*line == '}') 8986915dcf3SAlexander Graf break; 8996915dcf3SAlexander Graf 9006915dcf3SAlexander Graf if (*line) { 9016915dcf3SAlexander Graf line = skip_whitespace(line); 9026915dcf3SAlexander Graf entry->filename = line; 9036915dcf3SAlexander Graf nr_entries++; 9046915dcf3SAlexander Graf entry++; 9056915dcf3SAlexander Graf } 9066915dcf3SAlexander Graf 9076915dcf3SAlexander Graf /* Use next line */ 9086915dcf3SAlexander Graf bifp = bifpn; 9096915dcf3SAlexander Graf } 9106915dcf3SAlexander Graf 9116915dcf3SAlexander Graf for (i = 0; i < nr_entries; i++) { 9126915dcf3SAlexander Graf debug("Entry flags=%#lx name=%s\n", entries[i].flags, 9136915dcf3SAlexander Graf entries[i].filename); 9146915dcf3SAlexander Graf } 9156915dcf3SAlexander Graf 9166915dcf3SAlexander Graf /* 9176915dcf3SAlexander Graf * Some entries are actually configuration option for other ones, 9186915dcf3SAlexander Graf * let's apply them in an intermediate step. 9196915dcf3SAlexander Graf */ 9206915dcf3SAlexander Graf for (i = 0; i < nr_entries; i++) { 9216915dcf3SAlexander Graf struct bif_entry *entry = &entries[i]; 9226915dcf3SAlexander Graf 9236915dcf3SAlexander Graf if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG)) 9246915dcf3SAlexander Graf if (bif_fsbl_config(entry, entries, nr_entries)) 9256915dcf3SAlexander Graf goto err; 9266915dcf3SAlexander Graf } 9276915dcf3SAlexander Graf 9286915dcf3SAlexander Graf /* Make sure PMUFW comes before bootloader */ 9296915dcf3SAlexander Graf for (i = 0; i < nr_entries; i++) { 9306915dcf3SAlexander Graf struct bif_entry *entry = &entries[i]; 9316915dcf3SAlexander Graf 9326915dcf3SAlexander Graf if (entry->flags & (1ULL << BIF_FLAG_BOOTLOADER)) 9336915dcf3SAlexander Graf bldr = i; 9346915dcf3SAlexander Graf if (entry->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE)) { 9356915dcf3SAlexander Graf if (bldr >= 0) { 9366915dcf3SAlexander Graf struct bif_entry tmp = *entry; 9376915dcf3SAlexander Graf 9386915dcf3SAlexander Graf *entry = entries[bldr]; 9396915dcf3SAlexander Graf entries[bldr] = tmp; 9406915dcf3SAlexander Graf } 9416915dcf3SAlexander Graf } 9426915dcf3SAlexander Graf } 9436915dcf3SAlexander Graf 9446915dcf3SAlexander Graf for (i = 0; i < nr_entries; i++) { 9456915dcf3SAlexander Graf struct bif_entry *entry = &entries[i]; 9466915dcf3SAlexander Graf const struct bif_file_type *type; 9476915dcf3SAlexander Graf int r; 9486915dcf3SAlexander Graf 9496915dcf3SAlexander Graf if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG)) 9506915dcf3SAlexander Graf continue; 9516915dcf3SAlexander Graf 9526915dcf3SAlexander Graf type = get_file_type(entry); 9536915dcf3SAlexander Graf if (!type) 9546915dcf3SAlexander Graf goto err; 9556915dcf3SAlexander Graf 9566915dcf3SAlexander Graf debug("type=%s file=%s\n", type->name, entry->filename); 9576915dcf3SAlexander Graf r = type->add(entry); 9586915dcf3SAlexander Graf if (r) 9596915dcf3SAlexander Graf goto err; 9606915dcf3SAlexander Graf } 9616915dcf3SAlexander Graf 9626915dcf3SAlexander Graf /* Calculate checksums */ 9636915dcf3SAlexander Graf csum = zynqmp_csum(&bif_output.header->width_detection, 9646915dcf3SAlexander Graf &bif_output.header->checksum); 9656915dcf3SAlexander Graf bif_output.header->checksum = cpu_to_le32(csum); 9666915dcf3SAlexander Graf 9676915dcf3SAlexander Graf if (bif_output.imgheader) { 9686915dcf3SAlexander Graf csum = zynqmp_csum(bif_output.imgheader, 9696915dcf3SAlexander Graf &bif_output.imgheader->checksum); 9706915dcf3SAlexander Graf bif_output.imgheader->checksum = cpu_to_le32(csum); 9716915dcf3SAlexander Graf } 9726915dcf3SAlexander Graf 9736915dcf3SAlexander Graf /* Write headers and components */ 9746915dcf3SAlexander Graf if (lseek(outfd, 0, SEEK_SET) != 0) 9756915dcf3SAlexander Graf goto err; 9766915dcf3SAlexander Graf 9776915dcf3SAlexander Graf len = bif_output.data_len; 9786915dcf3SAlexander Graf bifp = bif_output.data; 9796915dcf3SAlexander Graf while (len) { 9806915dcf3SAlexander Graf int r; 9816915dcf3SAlexander Graf 9826915dcf3SAlexander Graf r = write(outfd, bifp, len); 9836915dcf3SAlexander Graf if (r < 0) 9846915dcf3SAlexander Graf goto err; 9856915dcf3SAlexander Graf len -= r; 9866915dcf3SAlexander Graf bifp += r; 9876915dcf3SAlexander Graf } 9886915dcf3SAlexander Graf 9896915dcf3SAlexander Graf return 0; 9906915dcf3SAlexander Graf 9916915dcf3SAlexander Graf err: 9926915dcf3SAlexander Graf fprintf(stderr, "Error: Failed to create image.\n"); 9936915dcf3SAlexander Graf return -1; 9946915dcf3SAlexander Graf } 9956915dcf3SAlexander Graf 9966915dcf3SAlexander Graf /* Needs to be stubbed out so we can print after creation */ 9976915dcf3SAlexander Graf static void zynqmpbif_set_header(void *ptr, struct stat *sbuf, int ifd, 9986915dcf3SAlexander Graf struct image_tool_params *params) 9996915dcf3SAlexander Graf { 10006915dcf3SAlexander Graf } 10016915dcf3SAlexander Graf 10026915dcf3SAlexander Graf static struct zynqmp_header zynqmpimage_header; 10036915dcf3SAlexander Graf 10046915dcf3SAlexander Graf U_BOOT_IMAGE_TYPE( 10056915dcf3SAlexander Graf zynqmpbif, 10066915dcf3SAlexander Graf "Xilinx ZynqMP Boot Image support (bif)", 10076915dcf3SAlexander Graf sizeof(struct zynqmp_header), 10086915dcf3SAlexander Graf (void *)&zynqmpimage_header, 10096915dcf3SAlexander Graf zynqmpbif_check_params, 10106915dcf3SAlexander Graf NULL, 10116915dcf3SAlexander Graf zynqmpimage_print_header, 10126915dcf3SAlexander Graf zynqmpbif_set_header, 10136915dcf3SAlexander Graf NULL, 10146915dcf3SAlexander Graf zynqmpbif_check_image_types, 10156915dcf3SAlexander Graf NULL, 10166915dcf3SAlexander Graf NULL 10176915dcf3SAlexander Graf ); 1018