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 <ag...@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, ¶ms); > + } else if (params.type == IH_TYPE_ZYNQMPBIF) { > + /* Image file is meta, walk through actual targets */ > + zynqmpbif_copy_image(ifd, ¶ms); 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 <ag...@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 _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot