forked from pool/u-boot
1176 lines
28 KiB
Diff
1176 lines
28 KiB
Diff
|
From b2c049d99b556e18860fdc7ab038c048003a90cc Mon Sep 17 00:00:00 2001
|
||
|
From: Alexander Graf <agraf@suse.de>
|
||
|
Date: Fri, 6 Apr 2018 13:45:18 +0200
|
||
|
Subject: [PATCH] tools: zynqmpimage: Add bif support
|
||
|
|
||
|
The officially described way to generate boot.bin files for ZynqMP is to
|
||
|
describe the contents of the target binary using a file of the "bif"
|
||
|
format. This file then links to other files that all get packed into a
|
||
|
bootable image.
|
||
|
|
||
|
This patch adds support to read such a .bif file and generate a respective
|
||
|
ZynqMP boot.bin file that can include the normal image and pmu files, but
|
||
|
also supports image partitions now. This makes it a handy replacement for
|
||
|
the proprietary "bootgen" utility that is currently used to generate
|
||
|
boot.bin files with FSBL.
|
||
|
|
||
|
Signed-off-by: Alexander Graf <agraf@suse.de>
|
||
|
|
||
|
---
|
||
|
|
||
|
v2 -> v3:
|
||
|
|
||
|
- zero initialize header
|
||
|
- reduce default debug verbosity
|
||
|
|
||
|
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 4eae585218..87d15010c0 100644
|
||
|
--- a/common/image.c
|
||
|
+++ b/common/image.c
|
||
|
@@ -158,6 +158,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 6a22c98b4a..8fa75a5a5a 100644
|
||
|
--- a/include/image.h
|
||
|
+++ b/include/image.h
|
||
|
@@ -268,6 +268,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 1185bf5b36..5dd33ed4d5 100644
|
||
|
--- a/tools/Makefile
|
||
|
+++ b/tools/Makefile
|
||
|
@@ -111,6 +111,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 ef2429e050..d191b9cfe7 100644
|
||
|
--- a/tools/imagetool.h
|
||
|
+++ b/tools/imagetool.h
|
||
|
@@ -231,6 +231,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 64ad131860..e0d4d20be4 100644
|
||
|
--- a/tools/mkimage.c
|
||
|
+++ b/tools/mkimage.c
|
||
|
@@ -515,6 +515,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@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 870a6b5710..19b2f02ff1 100644
|
||
|
--- a/tools/zynqmpimage.c
|
||
|
+++ b/tools/zynqmpimage.c
|
||
|
@@ -86,7 +86,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;
|
||
|
|
||
|
@@ -209,7 +209,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_ */
|