Hi Peter, I'm not sure how much documentation you want. Basically mkimage becomes a replacement for bootgen in any official Xilinx documentation. So any Xilinx wiki like
http://www.wiki.xilinx.com/Prepare+boot+image or even the official .bif documentation: https://www.xilinx.com/support/documentation/user_guides/ug1137-zynq-ultrascale-mpsoc-swdev.pdf apply. The only difference is that the command line arguments are different. But mkimage takes a .bif file as input and generates a boot.bin file as output. Alex On 13.06.18 08:49, Peter Robinson wrote: > Michael or Alex, > > Could someone add a ZynqMP README documenting the process required to > use U-Boot for the ZynqMP with the open tools? I looked in > board/xilinx/zynqmp and doc/ and a few other places but couldn't see > any docs for either that or the closed tools. > > Peter > > On Fri, Apr 13, 2018 at 1:18 PM, Alexander Graf <ag...@suse.de> 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 >> >> v3 -> v4: >> >> - add error handling >> - add fsbl_config support >> - add aarch32 support >> - allow a5x to be written as a53 >> - add offset support >> - add support for partition_owner >> - ensure pmufw comes before bootloader >> - simplify fsbl_config >> - add non-a53 boot support >> - checkpatch fixes >> --- >> common/image.c | 1 + >> include/image.h | 1 + >> tools/Makefile | 1 + >> tools/imagetool.h | 1 + >> tools/mkimage.c | 7 + >> tools/zynqmpbif.c | 1008 >> +++++++++++++++++++++++++++++++++++++++++++++++++++ >> tools/zynqmpimage.c | 4 +- >> tools/zynqmpimage.h | 7 + >> 8 files changed, 1028 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..6a7e7386f7 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); >> +int zynqmpbif_copy_image(int fd, struct image_tool_params *mparams); >> >> #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..fe861f5405 100644 >> --- a/tools/mkimage.c >> +++ b/tools/mkimage.c >> @@ -514,6 +514,13 @@ 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 */ >> + int ret; >> + >> + ret = zynqmpbif_copy_image(ifd, ¶ms); >> + if (ret) >> + return ret; >> } else { >> copy_file(ifd, params.datafile, pad_len); >> } >> diff --git a/tools/zynqmpbif.c b/tools/zynqmpbif.c >> new file mode 100644 >> index 0000000000..6c8f66055d >> --- /dev/null >> +++ b/tools/zynqmpbif.c >> @@ -0,0 +1,1008 @@ >> +/* >> + * 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; >> + size_t offset; >> +}; >> + >> +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, >> + BIF_FLAG_AARCH32, >> + BIF_FLAG_PART_OWNER_UBOOT, >> + >> + /* 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) >> +{ >> + uint64_t i; >> + >> + for (i = 0; i < ARRAY_SIZE(dest_cpus); i++) { >> + if (!strncmp(line, dest_cpus[i], strlen(dest_cpus[i]))) { >> + bf->dest_cpu = i << PART_ATTR_DEST_CPU_SHIFT; >> + return line + strlen(dest_cpus[i]); >> + } >> + >> + /* a5x can also be written as a53 */ >> + if (!strncmp(dest_cpus[i], "a5x", 3)) { >> + char a53[] = "a53-X"; >> + >> + a53[4] = dest_cpus[i][4]; >> + if (!strncmp(line, a53, strlen(a53))) { >> + bf->dest_cpu = i << PART_ATTR_DEST_CPU_SHIFT; >> + return line + strlen(a53); >> + } >> + } >> + } >> + >> + 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 char *parse_offset(char *line, struct bif_entry *bf) >> +{ >> + char *endptr; >> + >> + bf->offset = strtoll(line, &endptr, 0); >> + >> + return endptr; >> +} >> + >> +static char *parse_partition_owner(char *line, struct bif_entry *bf) >> +{ >> + char *endptr = NULL; >> + >> + if (!strncmp(line, "fsbl", 4)) { >> + endptr = line + 4; >> + } else if (!strncmp(line, "uboot", 5)) { >> + bf->flags |= 1ULL << BIF_FLAG_PART_OWNER_UBOOT; >> + endptr = line + 5; >> + } else { >> + printf("ERROR: Unknown partition type '%s'\n", line); >> + } >> + >> + 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 }, >> + { "offset=", 0, parse_offset }, >> + { "partition_owner=", 0, parse_partition_owner }, >> +}; >> + >> +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; >> + >> + buf = malloc(sbuf.st_size); >> + if (!buf) >> + return NULL; >> + >> + bufp = buf; >> + 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; >> + uintptr_t header_off; >> + uintptr_t last_part_off; >> + uintptr_t imgheader_off; >> + uintptr_t old_data = (uintptr_t)bif_output.data; >> + void *new_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; >> + >> + if (offset && *offset) { >> + /* Pad to a given offset */ >> + if (bif_output.data_len > *offset) { >> + printf("Can not pad to offset %zx\n", *offset); >> + return -1; >> + } >> + >> + bif_output.data_len = *offset; >> + } >> + >> + new_size = ROUND(bif_output.data_len + len, 64); >> + new_data = realloc(bif_output.data, new_size); >> + memcpy(new_data + bif_output.data_len, data, len); >> + if (offset) >> + *offset = bif_output.data_len; >> + bif_output.data = new_data; >> + bif_output.data_len = new_size; >> + >> + /* Readjust internal pointers */ >> + if (bif_output.header) >> + bif_output.header = new_data + header_off; >> + if (bif_output.last_part) >> + bif_output.last_part = new_data + last_part_off; >> + if (bif_output.imgheader) >> + bif_output.imgheader = new_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) >> +{ >> + int r; >> + >> + if (bif_output.header->image_offset) { >> + printf("PMUFW expected before bootloader in your .bif >> file!\n"); >> + return -1; >> + } >> + >> + r = bif_add_blob(data, len, &bf->offset); >> + if (r) >> + return r; >> + >> + 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(bf->offset); >> + >> + return 0; >> +} >> + >> +static int bif_add_part(struct bif_entry *bf, const char *data, size_t len) >> +{ >> + size_t parthdr_offset = 0; >> + 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); >> + >> + r = bif_add_blob(data, len, &bf->offset); >> + if (r) >> + return r; >> + >> + parthdr.offset = cpu_to_le32(bf->offset / 4); >> + >> + if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) { >> + if (bif_output.last_part) { >> + printf("ERROR: Bootloader expected before others\n"); >> + return -1; >> + } >> + >> + parthdr.offset = >> cpu_to_le32(bif_output.header->image_offset); >> + parthdr.len = cpu_to_le32((bf->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; >> + if (bf->flags & (1ULL << BIF_FLAG_TZ)) >> + parthdr.attributes |= PART_ATTR_TZ_SECURE; >> + if (bf->flags & (1ULL << BIF_FLAG_PART_OWNER_UBOOT)) >> + parthdr.attributes |= PART_ATTR_PART_OWNER_UBOOT; >> + switch (bf->dest_cpu) { >> + case PART_ATTR_DEST_CPU_NONE: >> + case PART_ATTR_DEST_CPU_A53_0: >> + case PART_ATTR_DEST_CPU_A53_1: >> + case PART_ATTR_DEST_CPU_A53_2: >> + case PART_ATTR_DEST_CPU_A53_3: >> + if (bf->flags & (1ULL << BIF_FLAG_AARCH32)) >> + parthdr.attributes |= PART_ATTR_A53_EXEC_AARCH32; >> + } >> + >> + 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 = 0; >> + 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(bf->offset); >> + bif_output.header->image_size = cpu_to_le32(len); >> + bif_output.header->image_stored_size = cpu_to_le32(len); >> + >> + bif_output.header->image_attributes &= >> ~HEADER_CPU_SELECT_MASK; >> + switch (bf->dest_cpu) { >> + default: >> + case PART_ATTR_DEST_CPU_A53_0: >> + if (bf->flags & BIF_FLAG_AARCH32) >> + bif_output.header->image_attributes |= >> + HEADER_CPU_SELECT_A53_32BIT; >> + else >> + bif_output.header->image_attributes |= >> + HEADER_CPU_SELECT_A53_64BIT; >> + break; >> + case PART_ATTR_DEST_CPU_R5_0: >> + bif_output.header->image_attributes |= >> + HEADER_CPU_SELECT_R5_SINGLE; >> + break; >> + case PART_ATTR_DEST_CPU_R5_L: >> + bif_output.header->image_attributes |= >> + HEADER_CPU_SELECT_R5_DUAL; >> + break; >> + } >> + } >> + >> + 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++, shdr++) { >> + if (!shdr->sh_size || !shdr->sh_addr || >> + !(shdr->sh_flags & SHF_ALLOC) || >> + (shdr->sh_type == SHT_NOBITS)) >> + 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); >> + } >> + >> + *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++, shdr++) { >> + 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)) >> + continue; >> + >> + if (shdr->sh_type != SHT_NOBITS) >> + memcpy(dst, src, le64_to_cpu(shdr->sh_size)); >> + } >> + >> + 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++, shdr++) { >> + if (!shdr->sh_size || !shdr->sh_addr || >> + !(shdr->sh_flags & SHF_ALLOC) || >> + (shdr->sh_type == SHT_NOBITS)) >> + 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); >> + } >> + >> + *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++, shdr++) { >> + 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)) >> + continue; >> + >> + if (shdr->sh_type != SHT_NOBITS) >> + memcpy(dst, src, le32_to_cpu(shdr->sh_size)); >> + } >> + >> + 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); >> + bf->flags |= 1ULL << BIF_FLAG_AARCH32; >> + 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 int bif_fsbl_config(struct bif_entry *fsbl_config, >> + struct bif_entry *entries, int nr_entries) >> +{ >> + int i; >> + int config_set = 0; >> + struct { >> + const char *name; >> + uint64_t flags; >> + uint64_t dest_cpu; >> + } configs[] = { >> + { .name = "a5x_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 }, >> + { .name = "a53_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 }, >> + { .name = "a5x_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0, >> + .flags = 1ULL << BIF_FLAG_AARCH32 }, >> + { .name = "a53_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0, >> + .flags = 1ULL << BIF_FLAG_AARCH32 }, >> + { .name = "r5_single", .dest_cpu = PART_ATTR_DEST_CPU_R5_0 }, >> + { .name = "r5_dual", .dest_cpu = PART_ATTR_DEST_CPU_R5_L }, >> + }; >> + >> + /* Set target CPU of bootloader entry */ >> + for (i = 0; i < nr_entries; i++) { >> + struct bif_entry *b = &entries[i]; >> + const char *config_attr = fsbl_config->filename; >> + int j; >> + >> + if (!(b->flags & (1ULL << BIF_FLAG_BOOTLOADER))) >> + continue; >> + >> + for (j = 0; j < ARRAY_SIZE(configs); j++) { >> + if (!strncmp(config_attr, configs[j].name, >> + strlen(configs[j].name))) { >> + b->dest_cpu = configs[j].dest_cpu; >> + b->flags |= configs[j].flags; >> + config_set = 1; >> + } >> + } >> + >> + if (!config_set) { >> + printf("ERROR: Unsupported fsbl_config: %s\n", >> + config_attr); >> + return -1; >> + } >> + } >> + >> + if (!config_set) { >> + printf("ERROR: fsbl_config w/o bootloader\n"); >> + return -1; >> + } >> + >> + return 0; >> +} >> + >> +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; >> +} >> + >> +int 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; >> + int bldr = -1; >> + >> + bif_init(); >> + >> + /* Read .bif input file */ >> + 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'); >> + >> + if (bifpn[-1] == '\r') >> + bifpn[-1] = '\0'; >> + >> + *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; >> + >> + if (!line) >> + goto err; >> + >> + /* 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); >> + } >> + >> + /* >> + * Some entries are actually configuration option for other ones, >> + * let's apply them in an intermediate step. >> + */ >> + for (i = 0; i < nr_entries; i++) { >> + struct bif_entry *entry = &entries[i]; >> + >> + if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG)) >> + if (bif_fsbl_config(entry, entries, nr_entries)) >> + goto err; >> + } >> + >> + /* Make sure PMUFW comes before bootloader */ >> + for (i = 0; i < nr_entries; i++) { >> + struct bif_entry *entry = &entries[i]; >> + >> + if (entry->flags & (1ULL << BIF_FLAG_BOOTLOADER)) >> + bldr = i; >> + if (entry->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE)) { >> + if (bldr >= 0) { >> + struct bif_entry tmp = *entry; >> + >> + *entry = entries[bldr]; >> + entries[bldr] = tmp; >> + } >> + } >> + } >> + >> + for (i = 0; i < nr_entries; i++) { >> + struct bif_entry *entry = &entries[i]; >> + const struct bif_file_type *type; >> + int r; >> + >> + if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG)) >> + continue; >> + >> + 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 0; >> + >> +err: >> + fprintf(stderr, "Error: Failed to create image.\n"); >> + return -1; >> +} >> + >> +/* 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 3bd23b9bf8..288816d6cd 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; >> >> @@ -210,7 +210,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..7a57681709 100644 >> --- a/tools/zynqmpimage.h >> +++ b/tools/zynqmpimage.h >> @@ -19,7 +19,11 @@ >> #define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff)) >> #define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566)) >> #define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58)) >> +#define HEADER_CPU_SELECT_MASK (0x3 << 10) >> +#define HEADER_CPU_SELECT_R5_SINGLE (0x0 << 10) >> +#define HEADER_CPU_SELECT_A53_32BIT (0x1 << 10) >> #define HEADER_CPU_SELECT_A53_64BIT (0x2 << 10) >> +#define HEADER_CPU_SELECT_R5_DUAL (0x3 << 10) >> >> enum { >> ENCRYPTION_EFUSE = 0xa5c3c5a3, >> @@ -129,4 +133,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_ */ >> -- >> 2.12.3 >> >> _______________________________________________ >> U-Boot mailing list >> U-Boot@lists.denx.de >> https://lists.denx.de/listinfo/u-boot > _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot