All of lore.kernel.org
 help / color / mirror / Atom feed
From: Michal Simek <monstr@monstr.eu>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH v3 3/3] tools: zynqmpimage: Add bif support
Date: Fri, 13 Apr 2018 11:40:03 +0200	[thread overview]
Message-ID: <0ef7e9ea-764a-aa2b-6067-12091e91f5c0@monstr.eu> (raw)
In-Reply-To: <20180412134823.77239-4-agraf@suse.de>

On 12.4.2018 15:48, Alexander Graf wrote:
> The officially described way to generate boot.bin files for ZynqMP is to
> describe the contents of the target binary using a file of the "bif" format.
> This file then links to other files that all get packed into a bootable image.
> 
> This patch adds support to read such a .bif file and generate a respective
> ZynqMP boot.bin file that can include the normal image and pmu files, but also
> supports image partitions now. This makes it a handy replacement for the
> proprietary "bootgen" utility that is currently used to generate boot.bin
> files with FSBL.
> 
> Signed-off-by: Alexander Graf <agraf@suse.de>
> 
> ---
> 
> v2 -> v3:
> 
>   - zero initialize header
>   - reduce default debug verbosity
> ---
>  common/image.c      |   1 +
>  include/image.h     |   1 +
>  tools/Makefile      |   1 +
>  tools/imagetool.h   |   1 +
>  tools/mkimage.c     |   3 +
>  tools/zynqmpbif.c   | 839 ++++++++++++++++++++++++++++++++++++++++++++++++++++
>  tools/zynqmpimage.c |   4 +-
>  tools/zynqmpimage.h |   3 +
>  8 files changed, 851 insertions(+), 2 deletions(-)
>  create mode 100644 tools/zynqmpbif.c
> 
> diff --git a/common/image.c b/common/image.c
> index e1c50eb25d..f30dfa229b 100644
> --- a/common/image.c
> +++ b/common/image.c
> @@ -159,6 +159,7 @@ static const table_entry_t uimage_type[] = {
>  	{	IH_TYPE_VYBRIDIMAGE, "vybridimage",  "Vybrid Boot Image", },
>  	{	IH_TYPE_ZYNQIMAGE,  "zynqimage",  "Xilinx Zynq Boot Image" },
>  	{	IH_TYPE_ZYNQMPIMAGE, "zynqmpimage", "Xilinx ZynqMP Boot Image" },
> +	{	IH_TYPE_ZYNQMPBIF,  "zynqmpbif",  "Xilinx ZynqMP Boot Image (bif)" },
>  	{	IH_TYPE_FPGA,       "fpga",       "FPGA Image" },
>  	{       IH_TYPE_TEE,        "tee",        "Trusted Execution Environment Image",},
>  	{	IH_TYPE_FIRMWARE_IVT, "firmware_ivt", "Firmware with HABv4 IVT" },
> diff --git a/include/image.h b/include/image.h
> index a579c5f509..c5af912aeb 100644
> --- a/include/image.h
> +++ b/include/image.h
> @@ -269,6 +269,7 @@ enum {
>  	IH_TYPE_RKSPI,			/* Rockchip SPI image		*/
>  	IH_TYPE_ZYNQIMAGE,		/* Xilinx Zynq Boot Image */
>  	IH_TYPE_ZYNQMPIMAGE,		/* Xilinx ZynqMP Boot Image */
> +	IH_TYPE_ZYNQMPBIF,		/* Xilinx ZynqMP Boot Image (bif) */
>  	IH_TYPE_FPGA,			/* FPGA Image */
>  	IH_TYPE_VYBRIDIMAGE,	/* VYBRID .vyb Image */
>  	IH_TYPE_TEE,            /* Trusted Execution Environment OS Image */
> diff --git a/tools/Makefile b/tools/Makefile
> index 8143c25666..204685ec9e 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -113,6 +113,7 @@ dumpimage-mkimage-objs := aisimage.o \
>  			ublimage.o \
>  			zynqimage.o \
>  			zynqmpimage.o \
> +			zynqmpbif.o \
>  			$(LIBFDT_OBJS) \
>  			gpimage.o \
>  			gpimage-common.o \
> diff --git a/tools/imagetool.h b/tools/imagetool.h
> index e67de9b5ad..d78a9458f4 100644
> --- a/tools/imagetool.h
> +++ b/tools/imagetool.h
> @@ -232,6 +232,7 @@ time_t imagetool_get_source_date(
>  
>  
>  void pbl_load_uboot(int fd, struct image_tool_params *mparams);
> +void zynqmpbif_copy_image(int fd, struct image_tool_params *mparams);

This should return value which you will check

>  
>  #define ___cat(a, b) a ## b
>  #define __cat(a, b) ___cat(a, b)
> diff --git a/tools/mkimage.c b/tools/mkimage.c
> index 4e561820e7..72183f5f2b 100644
> --- a/tools/mkimage.c
> +++ b/tools/mkimage.c
> @@ -514,6 +514,9 @@ int main(int argc, char **argv)
>  		} else if (params.type == IH_TYPE_PBLIMAGE) {
>  			/* PBL has special Image format, implements its' own */
>  			pbl_load_uboot(ifd, &params);
> +		} else if (params.type == IH_TYPE_ZYNQMPBIF) {
> +			/* Image file is meta, walk through actual targets */
> +			zynqmpbif_copy_image(ifd, &params);

The same here because if there is for example comment in bif format
which is permitted than you need to error out.

>  		} else {
>  			copy_file(ifd, params.datafile, pad_len);
>  		}
> diff --git a/tools/zynqmpbif.c b/tools/zynqmpbif.c
> new file mode 100644
> index 0000000000..d60eff1d8b
> --- /dev/null
> +++ b/tools/zynqmpbif.c
> @@ -0,0 +1,839 @@
> +/*
> + * Copyright (C) 2018 Alexander Graf <agraf@suse.de>
> + *
> + * SPDX-License-Identifier:	GPL-2.0+
> + */
> +
> +#include "imagetool.h"
> +#include "mkimage.h"
> +#include "zynqmpimage.h"
> +#include <elf.h>
> +#include <image.h>
> +
> +struct bif_entry {
> +	const char *filename;
> +	uint64_t flags;
> +	uint64_t dest_cpu;
> +	uint64_t exp_lvl;
> +	uint64_t dest_dev;
> +	uint64_t load;
> +	uint64_t entry;
> +};
> +
> +enum bif_flag {
> +	BIF_FLAG_AESKEYFILE,
> +	BIF_FLAG_INIT,
> +	BIF_FLAG_UDF_BH,
> +	BIF_FLAG_HEADERSIGNATURE,
> +	BIF_FLAG_PPKFILE,
> +	BIF_FLAG_PSKFILE,
> +	BIF_FLAG_SPKFILE,
> +	BIF_FLAG_SSKFILE,
> +	BIF_FLAG_SPKSIGNATURE,
> +	BIF_FLAG_FSBL_CONFIG,
> +	BIF_FLAG_AUTH_PARAMS,
> +	BIF_FLAG_KEYSRC_ENCRYPTION,
> +	BIF_FLAG_PMUFW_IMAGE,
> +	BIF_FLAG_BOOTLOADER,
> +	BIF_FLAG_TZ,
> +	BIF_FLAG_BH_KEY_IV,
> +	BIF_FLAG_BH_KEYFILE,
> +	BIF_FLAG_PUF_FILE,
> +
> +	/* Internal flags */
> +	BIF_FLAG_BIT_FILE,
> +	BIF_FLAG_ELF_FILE,
> +	BIF_FLAG_BIN_FILE,
> +};
> +
> +struct bif_flags {
> +	const char name[32];
> +	uint64_t flag;
> +	char *(*parse)(char *line, struct bif_entry *bf);
> +};
> +
> +struct bif_file_type {
> +	const char name[32];
> +	uint32_t header;
> +	int (*add)(struct bif_entry *bf);
> +};
> +
> +struct bif_output {
> +	size_t data_len;
> +	char *data;
> +	struct image_header_table *imgheader;
> +	struct zynqmp_header *header;
> +	struct partition_header *last_part;
> +};
> +
> +struct bif_output bif_output;
> +
> +static uint32_t zynqmp_csum(void *start, void *end)
> +{
> +	uint32_t checksum = 0;
> +	uint32_t *ptr32 = start;
> +
> +	while (ptr32 != end) {
> +		checksum += le32_to_cpu(*ptr32);
> +		ptr32++;
> +	}
> +
> +	return ~checksum;
> +}
> +
> +static int zynqmpbif_check_params(struct image_tool_params *params)
> +{
> +	if (!params)
> +		return 0;
> +
> +	if (params->addr != 0x0) {
> +		fprintf(stderr, "Error: Load Address can not be specified.\n");
> +		return -1;
> +	}
> +
> +	if (params->eflag) {
> +		fprintf(stderr, "Error: Entry Point can not be specified.\n");
> +		return -1;
> +	}
> +
> +	return !(params->lflag || params->dflag);
> +}
> +
> +static int zynqmpbif_check_image_types(uint8_t type)
> +{
> +	return (type == IH_TYPE_ZYNQMPBIF) ? EXIT_SUCCESS : EXIT_FAILURE;
> +}
> +
> +static char *parse_dest_cpu(char *line, struct bif_entry *bf)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(dest_cpus); i++) {
> +		if (!strncmp(line, dest_cpus[i], strlen(dest_cpus[i]))) {
> +			bf->dest_cpu = i;
> +			return line + strlen(dest_cpus[i]);
> +		}
> +	}
> +
> +	return line;
> +}
> +
> +static char *parse_el(char *line, struct bif_entry *bf)
> +{
> +	const char *dest_els[] = { "none", "el-0", "el-1", "el-2", "el-3" };
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(dest_els); i++) {
> +		if (!strncmp(line, dest_els[i], strlen(dest_els[i]))) {
> +			bf->exp_lvl = i;
> +			return line + strlen(dest_els[i]);
> +		}
> +	}
> +
> +	return line;
> +}
> +
> +static char *parse_load(char *line, struct bif_entry *bf)
> +{
> +	char *endptr;
> +
> +	bf->load = strtoll(line, &endptr, 0);
> +
> +	return endptr;
> +}
> +
> +static char *parse_entry(char *line, struct bif_entry *bf)
> +{
> +	char *endptr;
> +
> +	bf->entry = strtoll(line, &endptr, 0);
> +
> +	return endptr;
> +}
> +
> +static const struct bif_flags bif_flags[] = {
> +	{ "fsbl_config", BIF_FLAG_FSBL_CONFIG },
> +	{ "trustzone", BIF_FLAG_TZ },
> +	{ "pmufw_image", BIF_FLAG_PMUFW_IMAGE },
> +	{ "bootloader", BIF_FLAG_BOOTLOADER },
> +	{ "destination_cpu=", 0, parse_dest_cpu },
> +	{ "exception_level=", 0, parse_el },
> +	{ "load=", 0, parse_load },
> +	{ "startup=", 0, parse_entry },
> +};
> +
> +static char *read_full_file(const char *filename, size_t *size)
> +{
> +	char *buf, *bufp;
> +	struct stat sbuf;
> +	int len = 0, r, fd;
> +
> +	fd = open(filename, O_RDONLY);
> +	if (fd < 0)
> +		return NULL;
> +
> +	if (fstat(fd, &sbuf) < 0)
> +		return NULL;
> +
> +	if (size)
> +		*size = sbuf.st_size;
> +
> +	bufp = buf = malloc(sbuf.st_size);
> +	if (!buf)
> +		return NULL;
> +
> +	while (len < sbuf.st_size) {
> +		r = read(fd, bufp, sbuf.st_size - len);
> +		if (r < 0)
> +			return NULL;
> +		len += r;
> +		bufp += r;
> +	}
> +
> +	close(fd);
> +
> +	return buf;
> +}
> +
> +static int bif_add_blob(const void *data, size_t len, size_t *offset)
> +{
> +	size_t new_size = ROUND(bif_output.data_len + len, 64);
> +	uintptr_t header_off;
> +	uintptr_t last_part_off;
> +	uintptr_t imgheader_off;
> +	uintptr_t old_data = (uintptr_t)bif_output.data;
> +
> +	header_off = (uintptr_t)bif_output.header - old_data;
> +	last_part_off = (uintptr_t)bif_output.last_part - old_data;
> +	imgheader_off = (uintptr_t)bif_output.imgheader - old_data;
> +
> +	bif_output.data = realloc(bif_output.data, new_size);
> +	memcpy(bif_output.data + bif_output.data_len, data, len);
> +	if (offset)
> +		*offset = bif_output.data_len;
> +	bif_output.data_len = new_size;
> +
> +	/* Readjust internal pointers */
> +	if (bif_output.header)
> +		bif_output.header = (void*)(bif_output.data + header_off);
> +	if (bif_output.last_part)
> +		bif_output.last_part = (void*)(bif_output.data + last_part_off);
> +	if (bif_output.imgheader)
> +		bif_output.imgheader = (void*)(bif_output.data + imgheader_off);
> +
> +	return 0;
> +}
> +
> +static int bif_init(void)
> +{
> +	struct zynqmp_header header = { { 0 } };
> +	int r;
> +
> +	zynqmpimage_default_header(&header);
> +
> +	r = bif_add_blob(&header, sizeof(header), NULL);
> +	if (r)
> +		return r;
> +
> +	bif_output.header = (void*)bif_output.data;
> +
> +	return 0;
> +}
> +
> +static int bif_add_pmufw(struct bif_entry *bf, const char *data, size_t len)
> +{
> +	size_t offset;
> +
> +	if (bif_output.header->image_offset) {
> +		printf("PMUFW expected before bootloader in your .bif file!\n");
> +		return -1;
> +	}
> +
> +	bif_add_blob(data, len, &offset);
> +	len = ROUND(len, 64);
> +	bif_output.header->pfw_image_length = cpu_to_le32(len);
> +	bif_output.header->total_pfw_image_length = cpu_to_le32(len);
> +	bif_output.header->image_offset = cpu_to_le32(offset);
> +
> +	return 0;
> +}
> +
> +static int bif_add_part(struct bif_entry *bf, const char *data, size_t len)
> +{
> +	size_t parthdr_offset, part_offset;
> +	struct partition_header parthdr = {
> +		.len_enc = cpu_to_le32(len / 4),
> +		.len_unenc = cpu_to_le32(len / 4),
> +		.len = cpu_to_le32(len / 4),
> +		.entry_point = cpu_to_le64(bf->entry),
> +		.load_address = cpu_to_le64(bf->load),
> +	};
> +	int r;
> +	uint32_t csum;
> +
> +	if (bf->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE))
> +		return bif_add_pmufw(bf, data, len);
> +
> +	bif_add_blob(data, len, &part_offset);
> +	parthdr.offset = cpu_to_le32(part_offset / 4);
> +
> +	if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) {
> +		if (bif_output.last_part) {
> +			printf("ERROR: Bootloader needs to come as first non-PMU partition");
> +			return -1;
> +		}
> +
> +		parthdr.offset = cpu_to_le32(bif_output.header->image_offset);
> +		parthdr.len = cpu_to_le32((part_offset + len -
> +			bif_output.header->image_offset) / 4);
> +		parthdr.len_enc = parthdr.len;
> +		parthdr.len_unenc = parthdr.len;
> +	}
> +
> +	/* Normalize EL */
> +	bf->exp_lvl = bf->exp_lvl ? bf->exp_lvl - 1 : 3;
> +	parthdr.attributes |= bf->exp_lvl << PART_ATTR_TARGET_EL_SHIFT;
> +	parthdr.attributes |= bf->dest_dev;
> +	parthdr.attributes |= bf->dest_cpu << PART_ATTR_DEST_CPU_SHIFT;
> +	if (bf->flags & (1ULL << BIF_FLAG_TZ))
> +		parthdr.attributes |= PART_ATTR_TZ_SECURE;
> +
> +	csum = zynqmp_csum(&parthdr, &parthdr.checksum);
> +	parthdr.checksum = cpu_to_le32(csum);
> +
> +	r = bif_add_blob(&parthdr, sizeof(parthdr), &parthdr_offset);
> +	if (r)
> +		return r;
> +
> +	/* Add image header table if not there yet */
> +	if (!bif_output.imgheader) {
> +		size_t imghdr_off;
> +		struct image_header_table imghdr = {
> +			.version = cpu_to_le32(0x01020000),
> +			.nr_parts = 0,
> +		};
> +
> +		r = bif_add_blob(&imghdr, sizeof(imghdr), &imghdr_off);
> +		if (r)
> +			return r;
> +
> +		bif_output.header->image_header_table_offset = imghdr_off;
> +		bif_output.imgheader = (void*)(bif_output.data + imghdr_off);
> +	}
> +
> +	bif_output.imgheader->nr_parts = cpu_to_le32(le32_to_cpu(
> +		bif_output.imgheader->nr_parts) + 1);
> +
> +	/* Link to this partition header */
> +	if (bif_output.last_part) {
> +		bif_output.last_part->next_partition_offset =
> +			cpu_to_le32(parthdr_offset / 4);
> +
> +		/* Recalc checksum of last_part */
> +		csum = zynqmp_csum(bif_output.last_part,
> +				   &bif_output.last_part->checksum);
> +		bif_output.last_part->checksum = cpu_to_le32(csum);
> +	} else {
> +		bif_output.imgheader->partition_header_offset =
> +			cpu_to_le32(parthdr_offset / 4);
> +	}
> +	bif_output.last_part = (void*)(bif_output.data + parthdr_offset);
> +
> +	if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) {
> +		bif_output.header->image_load = cpu_to_le32(bf->load);
> +		if (!bif_output.header->image_offset)
> +			bif_output.header->image_offset =
> +				cpu_to_le32(part_offset);
> +		bif_output.header->image_size = cpu_to_le32(len);
> +		bif_output.header->image_stored_size = cpu_to_le32(len);
> +	}
> +
> +	return 0;
> +}
> +
> +/* Add .bit bitstream */
> +static int bif_add_bit(struct bif_entry *bf)
> +{
> +	char *bit = read_full_file(bf->filename, NULL);
> +	char *bitbin;
> +	uint8_t initial_header[] = { 0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f,
> +				     0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01, 0x61 };
> +	uint16_t len;
> +	uint32_t bitlen;
> +	int i;
> +
> +	if (!bit)
> +		return -1;
> +
> +	/* Skip initial header */
> +	if (memcmp(bit, initial_header, sizeof(initial_header)))
> +		return -1;
> +
> +	bit += sizeof(initial_header);
> +
> +	/* Design name */
> +	len = be16_to_cpu(*(uint16_t*)bit);
> +	bit += sizeof(uint16_t);
> +	debug("Design: %s\n", bit);
> +	bit += len;
> +
> +	/* Device identifier */
> +	if (*bit != 'b')
> +		return -1;
> +	bit++;
> +	len = be16_to_cpu(*(uint16_t*)bit);
> +	bit += sizeof(uint16_t);
> +	debug("Device: %s\n", bit);
> +	bit += len;
> +
> +	/* Date */
> +	if (*bit != 'c')
> +		return -1;
> +	bit++;
> +	len = be16_to_cpu(*(uint16_t*)bit);
> +	bit += sizeof(uint16_t);
> +	debug("Date: %s\n", bit);
> +	bit += len;
> +
> +	/* Time */
> +	if (*bit != 'd')
> +		return -1;
> +	bit++;
> +	len = be16_to_cpu(*(uint16_t*)bit);
> +	bit += sizeof(uint16_t);
> +	debug("Time: %s\n", bit);
> +	bit += len;
> +
> +	/* Bitstream length */
> +	if (*bit != 'e')
> +		return -1;
> +	bit++;
> +	bitlen = be32_to_cpu(*(uint32_t*)bit);
> +	bit += sizeof(uint32_t);
> +	bitbin = bit;
> +
> +	debug("Bitstream Length: 0x%x\n", bitlen);
> +	for (i = 0; i < bitlen; i += sizeof(uint32_t)) {
> +		uint32_t *bitbin32 = (uint32_t*)&bitbin[i];
> +		*bitbin32 = __swab32(*bitbin32);
> +	}
> +
> +	if (!bf->dest_dev)
> +		bf->dest_dev = PART_ATTR_DEST_DEVICE_PL;
> +
> +	bf->load = 0xffffffff;
> +	bf->entry = 0;
> +
> +	bf->flags |= 1ULL << BIF_FLAG_BIT_FILE;
> +	return bif_add_part(bf, bit, bitlen);
> +}
> +
> +/* Add .bin bitstream */
> +static int bif_add_bin(struct bif_entry *bf)
> +{
> +	size_t size;
> +	char *bin = read_full_file(bf->filename, &size);
> +
> +	if (!bf->dest_dev)
> +		bf->dest_dev = PART_ATTR_DEST_DEVICE_PS;
> +
> +	bf->flags |= 1ULL << BIF_FLAG_BIN_FILE;
> +	return bif_add_part(bf, bin, size);
> +}
> +
> +/* Add elf file */
> +static char *elf2flat64(char *elf, size_t *flat_size, size_t *load_addr)
> +{
> +	Elf64_Ehdr *ehdr;
> +	Elf64_Shdr *shdr;
> +	size_t min_addr = -1, max_addr = 0;
> +	char *flat;
> +	int i;
> +
> +	ehdr = (void*)elf;
> +	shdr = (void*)(elf + le64_to_cpu(ehdr->e_shoff));
> +
> +	/* Look for smallest / biggest address */
> +	for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++) {
> +		if (!shdr->sh_size || !shdr->sh_addr ||
> +		    !(shdr->sh_flags & SHF_ALLOC) ||
> +		    (shdr->sh_type == SHT_NOBITS)) {
> +			shdr++;
> +			continue;
> +		}
> +
> +		if (le64_to_cpu(shdr->sh_addr) < min_addr)
> +			min_addr = le64_to_cpu(shdr->sh_addr);
> +		if ((le64_to_cpu(shdr->sh_addr) + le64_to_cpu(shdr->sh_size)) >
> +			max_addr)
> +			max_addr = le64_to_cpu(shdr->sh_addr) +
> +				   le64_to_cpu(shdr->sh_size);
> +
> +		shdr++;
> +	}
> +
> +	*load_addr = min_addr;
> +	*flat_size = max_addr - min_addr;
> +	flat = calloc(1, *flat_size);
> +	if (!flat)
> +		return NULL;
> +
> +	shdr = (void*)(elf + le64_to_cpu(ehdr->e_shoff));
> +	for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++) {
> +		char *dst = flat + le64_to_cpu(shdr->sh_addr) - min_addr;
> +		char *src = elf + le64_to_cpu(shdr->sh_offset);
> +
> +		if (!shdr->sh_size || !shdr->sh_addr ||
> +		    !(shdr->sh_flags & SHF_ALLOC)) {
> +			shdr++;
> +			continue;
> +		}
> +
> +		if (shdr->sh_type != SHT_NOBITS) {
> +
> +			memcpy(dst, src, le64_to_cpu(shdr->sh_size));
> +		}
> +		shdr++;
> +	}
> +
> +	return flat;
> +}
> +
> +static char *elf2flat32(char *elf, size_t *flat_size, size_t *load_addr)
> +{
> +	Elf32_Ehdr *ehdr;
> +	Elf32_Shdr *shdr;
> +	size_t min_addr = -1, max_addr = 0;
> +	char *flat;
> +	int i;
> +
> +	ehdr = (void*)elf;
> +	shdr = (void*)(elf + le32_to_cpu(ehdr->e_shoff));
> +
> +	/* Look for smallest / biggest address */
> +	for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++) {
> +		if (!shdr->sh_size || !shdr->sh_addr ||
> +		    !(shdr->sh_flags & SHF_ALLOC) ||
> +		    (shdr->sh_type == SHT_NOBITS)) {
> +			shdr++;
> +			continue;
> +		}
> +
> +		if (le32_to_cpu(shdr->sh_addr) < min_addr)
> +			min_addr = le32_to_cpu(shdr->sh_addr);
> +		if ((le32_to_cpu(shdr->sh_addr) + le32_to_cpu(shdr->sh_size)) >
> +			max_addr)
> +			max_addr = le32_to_cpu(shdr->sh_addr) +
> +				   le32_to_cpu(shdr->sh_size);
> +
> +		shdr++;
> +	}
> +
> +	*load_addr = min_addr;
> +	*flat_size = max_addr - min_addr;
> +	flat = calloc(1, *flat_size);
> +	if (!flat)
> +		return NULL;
> +
> +	shdr = (void*)(elf + le32_to_cpu(ehdr->e_shoff));
> +	for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++) {
> +		char *dst = flat + le32_to_cpu(shdr->sh_addr) - min_addr;
> +		char *src = elf + le32_to_cpu(shdr->sh_offset);
> +
> +		if (!shdr->sh_size || !shdr->sh_addr ||
> +		    !(shdr->sh_flags & SHF_ALLOC)) {
> +			shdr++;
> +			continue;
> +		}
> +
> +		if (shdr->sh_type != SHT_NOBITS) {
> +
> +			memcpy(dst, src, le32_to_cpu(shdr->sh_size));
> +		}
> +		shdr++;
> +	}
> +
> +	return flat;
> +}
> +
> +static int bif_add_elf(struct bif_entry *bf)
> +{
> +	size_t size;
> +	size_t elf_size;
> +	char *elf;
> +	char *flat;
> +	size_t load_addr;
> +	Elf32_Ehdr *ehdr32;
> +	Elf64_Ehdr *ehdr64;
> +
> +	elf = read_full_file(bf->filename, &elf_size);
> +	if (!elf)
> +		return -1;
> +
> +	ehdr32 = (void*)elf;
> +	ehdr64 = (void*)elf;
> +
> +	switch (ehdr32->e_ident[EI_CLASS]) {
> +	case ELFCLASS32:
> +		flat = elf2flat32(elf, &size, &load_addr);
> +		bf->entry = le32_to_cpu(ehdr32->e_entry);
> +		break;
> +	case ELFCLASS64:
> +		flat = elf2flat64(elf, &size, &load_addr);
> +		bf->entry = le64_to_cpu(ehdr64->e_entry);
> +		break;
> +	default:
> +		printf("Unknown ELF class: %d\n", ehdr32->e_ident[EI_CLASS]);
> +		return -1;
> +	}
> +
> +	if (!flat)
> +		return -1;
> +
> +	bf->load = load_addr;
> +	if (!bf->dest_dev)
> +		bf->dest_dev = PART_ATTR_DEST_DEVICE_PS;
> +
> +	bf->flags |= 1ULL << BIF_FLAG_ELF_FILE;
> +	return bif_add_part(bf, flat, size);
> +}
> +
> +static const struct bif_file_type bif_file_types[] = {
> +	{
> +		.name = "bitstream (.bit)",
> +		.header = 0x00090ff0,
> +		.add = bif_add_bit,
> +	},
> +
> +	{
> +		.name = "ELF",
> +		.header = 0x7f454c46,
> +		.add = bif_add_elf,
> +	},
> +
> +	/* Anything else is a .bin file */
> +	{
> +		.name = ".bin",
> +		.add = bif_add_bin,
> +	},
> +};
> +
> +static const struct bif_flags *find_flag(char *str)
> +{
> +	const struct bif_flags *bf;
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(bif_flags); i++) {
> +		bf = &bif_flags[i];
> +		if (!strncmp(bf->name, str, strlen(bf->name)))
> +			return bf;
> +	}
> +
> +	printf("ERROR: Flag '%s' not found\n", str);
> +
> +	return NULL;
> +}
> +
> +static int bif_open_file(struct bif_entry *entry)
> +{
> +	int fd = open(entry->filename, O_RDONLY);
> +
> +	if (fd < 0)
> +		printf("Error opening file %s\n", entry->filename);
> +
> +	return fd;
> +}
> +
> +static const struct bif_file_type *get_file_type(struct bif_entry *entry)
> +{
> +	int fd = bif_open_file(entry);
> +	uint32_t header;
> +	int i;
> +
> +	if (fd < 0)
> +		return NULL;
> +
> +	if (read(fd, &header, sizeof(header)) != sizeof(header)) {
> +		printf("Error reading file %s", entry->filename);
> +		return NULL;
> +	}
> +
> +	close(fd);
> +
> +	for (i = 0; i < ARRAY_SIZE(bif_file_types); i++) {
> +		const struct bif_file_type *type = &bif_file_types[i];
> +
> +		if (!type->header)
> +			return type;
> +		if (type->header == be32_to_cpu(header))
> +			return type;
> +	}
> +
> +	return NULL;
> +}
> +
> +#define NEXT_CHAR(str, chr) ({		\
> +	char *_n = strchr(str, chr);	\
> +	if (!_n)			\
> +		goto err;		\
> +	_n;				\
> +})
> +
> +static char *skip_whitespace(char *str)
> +{
> +	while (*str == ' ' || *str == '\t')
> +		str++;
> +
> +	return str;
> +}
> +
> +void zynqmpbif_copy_image(int outfd, struct image_tool_params *mparams)
> +{
> +	char *bif, *bifp, *bifpn;
> +	char *line;
> +	struct bif_entry entries[32] = { { 0 } };
> +	int nr_entries = 0;
> +	struct bif_entry *entry = entries;
> +	size_t len;
> +	int i;
> +	uint32_t csum;
> +
> +	bif_init();
> +
> +	/* Read .bif input file */
> +	bifp = bif = read_full_file(mparams->datafile, NULL);
> +	if (!bif)
> +		goto err;
> +
> +	/* Interpret .bif file */
> +	bifp = bif;
> +
> +	/* A bif description starts with a { section */
> +	bifp = NEXT_CHAR(bifp, '{') + 1;
> +
> +	/* Read every line */
> +	while (1) {
> +		bifpn = NEXT_CHAR(bifp, '\n');
> +
> +		*bifpn = '\0';
> +		bifpn++;
> +		line = bifp;
> +
> +		line = skip_whitespace(line);
> +
> +		/* Attributes? */
> +		if (*line == '[') {
> +			line++;
> +			while (1) {
> +				const struct bif_flags *bf;
> +
> +				line = skip_whitespace(line);
> +				bf = find_flag(line);
> +				if (!bf)
> +					goto err;
> +
> +				line += strlen(bf->name);
> +				if (bf->parse)
> +					line = bf->parse(line, entry);
> +				else
> +					entry->flags |= 1ULL << bf->flag;
> +
> +				/* Go to next attribute or quit */
> +				if (*line == ']') {
> +					line++;
> +					break;
> +				}
> +				if (*line == ',')
> +					line++;
> +			}
> +		}
> +
> +		/* End of image description */
> +		if (*line == '}')
> +			break;
> +
> +		if (*line) {
> +			line = skip_whitespace(line);
> +			entry->filename = line;
> +			nr_entries++;
> +			entry++;
> +		}
> +
> +		/* Use next line */
> +		bifp = bifpn;
> +	}
> +
> +	for (i = 0; i < nr_entries; i++) {
> +		debug("Entry flags=%#lx name=%s\n", entries[i].flags,
> +		      entries[i].filename);
> +	}
> +
> +	for (i = 0; i < nr_entries; i++) {
> +		struct bif_entry *entry = &entries[i];
> +		const struct bif_file_type *type;
> +		int r;
> +
> +		type = get_file_type(entry);
> +		if (!type)
> +			goto err;
> +
> +		debug("type=%s file=%s\n", type->name, entry->filename);
> +		r = type->add(entry);
> +		if (r)
> +			goto err;
> +	}
> +
> +	/* Calculate checksums */
> +	csum = zynqmp_csum(&bif_output.header->width_detection,
> +			   &bif_output.header->checksum);
> +	bif_output.header->checksum = cpu_to_le32(csum);
> +
> +	if (bif_output.imgheader) {
> +		csum = zynqmp_csum(bif_output.imgheader,
> +				   &bif_output.imgheader->checksum);
> +		bif_output.imgheader->checksum = cpu_to_le32(csum);
> +	}
> +
> +	/* Write headers and components */
> +	if (lseek(outfd, 0, SEEK_SET) != 0)
> +		goto err;
> +
> +	len = bif_output.data_len;
> +	bifp = bif_output.data;
> +	while (len) {
> +		int r;
> +		r = write(outfd, bifp, len);
> +		if (r < 0)
> +			goto err;
> +		len -= r;
> +		bifp += r;
> +	}
> +
> +	return;
> +
> +err:
> +	fprintf(stderr, "Error: Failed to create image.\n");
> +}
> +
> +/* Needs to be stubbed out so we can print after creation */
> +static void zynqmpbif_set_header(void *ptr, struct stat *sbuf, int ifd,
> +		struct image_tool_params *params)
> +{
> +}
> +
> +static struct zynqmp_header zynqmpimage_header;
> +
> +U_BOOT_IMAGE_TYPE(
> +	zynqmpbif,
> +	"Xilinx ZynqMP Boot Image support (bif)",
> +	sizeof(struct zynqmp_header),
> +	(void *)&zynqmpimage_header,
> +	zynqmpbif_check_params,
> +	NULL,
> +	zynqmpimage_print_header,
> +	zynqmpbif_set_header,
> +	NULL,
> +	zynqmpbif_check_image_types,
> +	NULL,
> +	NULL
> +);
> diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c
> index 8f4766f077..145391de3e 100644
> --- a/tools/zynqmpimage.c
> +++ b/tools/zynqmpimage.c
> @@ -87,7 +87,7 @@ static uint32_t zynqmpimage_checksum(struct zynqmp_header *ptr)
>  	return cpu_to_le32(checksum);
>  }
>  
> -static void zynqmpimage_default_header(struct zynqmp_header *ptr)
> +void zynqmpimage_default_header(struct zynqmp_header *ptr)
>  {
>  	int i;
>  
> @@ -211,7 +211,7 @@ static void print_partition(const void *ptr, const struct partition_header *ph)
>  	printf("    Checksum   : 0x%08x\n", le32_to_cpu(ph->checksum));
>  }
>  
> -static void zynqmpimage_print_header(const void *ptr)
> +void zynqmpimage_print_header(const void *ptr)
>  {
>  	struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr;
>  	int i;
> diff --git a/tools/zynqmpimage.h b/tools/zynqmpimage.h
> index f3b5c195ad..b421e4f94c 100644
> --- a/tools/zynqmpimage.h
> +++ b/tools/zynqmpimage.h
> @@ -129,4 +129,7 @@ struct zynqmp_header {
>  	uint32_t __reserved4[66]; /* 0x9c0 */
>  };
>  
> +void zynqmpimage_default_header(struct zynqmp_header *ptr);
> +void zynqmpimage_print_header(const void *ptr);
> +
>  #endif /* _ZYNQMPIMAGE_H_ */
> 

Also please run checkpatch over it.

Thanks,
Michal

-- 
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID: FE3D1F91
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Xilinx Microblaze
Maintainer of Linux kernel - Xilinx Zynq ARM and ZynqMP ARM64 SoCs
U-Boot custodian - Xilinx Microblaze/Zynq/ZynqMP SoCs

      reply	other threads:[~2018-04-13  9:40 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-04-12 13:48 [U-Boot] [PATCH v3 0/3] tools: zynqmpimage: Support partitions Alexander Graf
2018-04-12 13:48 ` [U-Boot] [PATCH v3 1/3] tools: zynqmpimage: Add partition read support Alexander Graf
2018-04-13  9:40   ` Michal Simek
2018-04-12 13:48 ` [U-Boot] [PATCH v3 2/3] tools: zynqmpimage: Move defines to header Alexander Graf
2018-04-12 13:48 ` [U-Boot] [PATCH v3 3/3] tools: zynqmpimage: Add bif support Alexander Graf
2018-04-13  9:40   ` Michal Simek [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=0ef7e9ea-764a-aa2b-6067-12091e91f5c0@monstr.eu \
    --to=monstr@monstr.eu \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.