Hi Alex On Wed, Jun 13, 2018 at 11:07 AM, Alexander Graf <[email protected]> wrote: > 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.
Thanks, good resources, a readme like doc/README.chromium outlining the process for people wanting to get started would likely be a good thing in general with links to those sorts of other resources would be useful for zynqmp like most of the other device categories. I was kind of surprised actually that zynqmp didn't have some sort of related docs to deal with it already. Thanks > 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 <[email protected]> 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 <[email protected]> >>> >>> --- >>> >>> 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 <[email protected]> >>> + * >>> + * 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 >>> [email protected] >>> https://lists.denx.de/listinfo/u-boot >> _______________________________________________ U-Boot mailing list [email protected] https://lists.denx.de/listinfo/u-boot

