[U-Boot] [PATCH v4 4/4] tools: zynqmpimage: Add bif support
Peter Robinson
pbrobinson at gmail.com
Wed Jun 13 12:56:35 UTC 2018
Hi Alex
On Wed, Jun 13, 2018 at 11:07 AM, Alexander Graf <agraf at suse.de> 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 <agraf at 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 <agraf at 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 <agraf at 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 at lists.denx.de
>>> https://lists.denx.de/listinfo/u-boot
>>
More information about the U-Boot
mailing list