xref: /openbmc/u-boot/tools/zynqmpbif.c (revision ce0d1e48165fdd3bde4bb431f1d2e100b1617a6e)
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 
zynqmp_csum(void * start,void * end)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 
zynqmpbif_check_params(struct image_tool_params * params)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 
zynqmpbif_check_image_types(uint8_t type)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 
parse_dest_cpu(char * line,struct bif_entry * bf)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 
parse_el(char * line,struct bif_entry * bf)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 
parse_load(char * line,struct bif_entry * bf)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 
parse_entry(char * line,struct bif_entry * bf)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 
parse_offset(char * line,struct bif_entry * bf)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 
parse_partition_owner(char * line,struct bif_entry * bf)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 
read_full_file(const char * filename,size_t * size)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 
bif_add_blob(const void * data,size_t len,size_t * offset)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 
bif_init(void)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 
bif_add_pmufw(struct bif_entry * bf,const char * data,size_t len)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 
bif_add_part(struct bif_entry * bf,const char * data,size_t len)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 */
bif_add_bit(struct bif_entry * bf)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 */
bif_add_bin(struct bif_entry * bf)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 */
elf2flat64(char * elf,size_t * flat_size,size_t * load_addr)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 
elf2flat32(char * elf,size_t * flat_size,size_t * load_addr)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 
bif_add_elf(struct bif_entry * bf)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 
bif_fsbl_config(struct bif_entry * fsbl_config,struct bif_entry * entries,int nr_entries)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 
find_flag(char * str)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 
bif_open_file(struct bif_entry * entry)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 
get_file_type(struct bif_entry * entry)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 
skip_whitespace(char * str)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 
zynqmpbif_copy_image(int outfd,struct image_tool_params * mparams)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 */
zynqmpbif_set_header(void * ptr,struct stat * sbuf,int ifd,struct image_tool_params * params)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