
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@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@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@suse.de
- SPDX-License-Identifier: GPL-2.0+
- */
+#include "imagetool.h" +#include "mkimage.h" +#include "zynqmpimage.h" +#include <elf.h> +#include <image.h>
+struct bif_entry {
const char *filename;
uint64_t flags;
uint64_t dest_cpu;
uint64_t exp_lvl;
uint64_t dest_dev;
uint64_t load;
uint64_t entry;
size_t offset;
+};
+enum bif_flag {
BIF_FLAG_AESKEYFILE,
BIF_FLAG_INIT,
BIF_FLAG_UDF_BH,
BIF_FLAG_HEADERSIGNATURE,
BIF_FLAG_PPKFILE,
BIF_FLAG_PSKFILE,
BIF_FLAG_SPKFILE,
BIF_FLAG_SSKFILE,
BIF_FLAG_SPKSIGNATURE,
BIF_FLAG_FSBL_CONFIG,
BIF_FLAG_AUTH_PARAMS,
BIF_FLAG_KEYSRC_ENCRYPTION,
BIF_FLAG_PMUFW_IMAGE,
BIF_FLAG_BOOTLOADER,
BIF_FLAG_TZ,
BIF_FLAG_BH_KEY_IV,
BIF_FLAG_BH_KEYFILE,
BIF_FLAG_PUF_FILE,
BIF_FLAG_AARCH32,
BIF_FLAG_PART_OWNER_UBOOT,
/* Internal flags */
BIF_FLAG_BIT_FILE,
BIF_FLAG_ELF_FILE,
BIF_FLAG_BIN_FILE,
+};
+struct bif_flags {
const char name[32];
uint64_t flag;
char *(*parse)(char *line, struct bif_entry *bf);
+};
+struct bif_file_type {
const char name[32];
uint32_t header;
int (*add)(struct bif_entry *bf);
+};
+struct bif_output {
size_t data_len;
char *data;
struct image_header_table *imgheader;
struct zynqmp_header *header;
struct partition_header *last_part;
+};
+struct bif_output bif_output;
+static uint32_t zynqmp_csum(void *start, void *end) +{
uint32_t checksum = 0;
uint32_t *ptr32 = start;
while (ptr32 != end) {
checksum += le32_to_cpu(*ptr32);
ptr32++;
}
return ~checksum;
+}
+static int zynqmpbif_check_params(struct image_tool_params *params) +{
if (!params)
return 0;
if (params->addr != 0x0) {
fprintf(stderr, "Error: Load Address can not be specified.\n");
return -1;
}
if (params->eflag) {
fprintf(stderr, "Error: Entry Point can not be specified.\n");
return -1;
}
return !(params->lflag || params->dflag);
+}
+static int zynqmpbif_check_image_types(uint8_t type) +{
return (type == IH_TYPE_ZYNQMPBIF) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+static char *parse_dest_cpu(char *line, struct bif_entry *bf) +{
uint64_t i;
for (i = 0; i < ARRAY_SIZE(dest_cpus); i++) {
if (!strncmp(line, dest_cpus[i], strlen(dest_cpus[i]))) {
bf->dest_cpu = i << PART_ATTR_DEST_CPU_SHIFT;
return line + strlen(dest_cpus[i]);
}
/* a5x can also be written as a53 */
if (!strncmp(dest_cpus[i], "a5x", 3)) {
char a53[] = "a53-X";
a53[4] = dest_cpus[i][4];
if (!strncmp(line, a53, strlen(a53))) {
bf->dest_cpu = i << PART_ATTR_DEST_CPU_SHIFT;
return line + strlen(a53);
}
}
}
return line;
+}
+static char *parse_el(char *line, struct bif_entry *bf) +{
const char *dest_els[] = { "none", "el-0", "el-1", "el-2", "el-3" };
int i;
for (i = 0; i < ARRAY_SIZE(dest_els); i++) {
if (!strncmp(line, dest_els[i], strlen(dest_els[i]))) {
bf->exp_lvl = i;
return line + strlen(dest_els[i]);
}
}
return line;
+}
+static char *parse_load(char *line, struct bif_entry *bf) +{
char *endptr;
bf->load = strtoll(line, &endptr, 0);
return endptr;
+}
+static char *parse_entry(char *line, struct bif_entry *bf) +{
char *endptr;
bf->entry = strtoll(line, &endptr, 0);
return endptr;
+}
+static char *parse_offset(char *line, struct bif_entry *bf) +{
char *endptr;
bf->offset = strtoll(line, &endptr, 0);
return endptr;
+}
+static char *parse_partition_owner(char *line, struct bif_entry *bf) +{
char *endptr = NULL;
if (!strncmp(line, "fsbl", 4)) {
endptr = line + 4;
} else if (!strncmp(line, "uboot", 5)) {
bf->flags |= 1ULL << BIF_FLAG_PART_OWNER_UBOOT;
endptr = line + 5;
} else {
printf("ERROR: Unknown partition type '%s'\n", line);
}
return endptr;
+}
+static const struct bif_flags bif_flags[] = {
{ "fsbl_config", BIF_FLAG_FSBL_CONFIG },
{ "trustzone", BIF_FLAG_TZ },
{ "pmufw_image", BIF_FLAG_PMUFW_IMAGE },
{ "bootloader", BIF_FLAG_BOOTLOADER },
{ "destination_cpu=", 0, parse_dest_cpu },
{ "exception_level=", 0, parse_el },
{ "load=", 0, parse_load },
{ "startup=", 0, parse_entry },
{ "offset=", 0, parse_offset },
{ "partition_owner=", 0, parse_partition_owner },
+};
+static char *read_full_file(const char *filename, size_t *size) +{
char *buf, *bufp;
struct stat sbuf;
int len = 0, r, fd;
fd = open(filename, O_RDONLY);
if (fd < 0)
return NULL;
if (fstat(fd, &sbuf) < 0)
return NULL;
if (size)
*size = sbuf.st_size;
buf = malloc(sbuf.st_size);
if (!buf)
return NULL;
bufp = buf;
while (len < sbuf.st_size) {
r = read(fd, bufp, sbuf.st_size - len);
if (r < 0)
return NULL;
len += r;
bufp += r;
}
close(fd);
return buf;
+}
+static int bif_add_blob(const void *data, size_t len, size_t *offset) +{
size_t new_size;
uintptr_t header_off;
uintptr_t last_part_off;
uintptr_t imgheader_off;
uintptr_t old_data = (uintptr_t)bif_output.data;
void *new_data;
header_off = (uintptr_t)bif_output.header - old_data;
last_part_off = (uintptr_t)bif_output.last_part - old_data;
imgheader_off = (uintptr_t)bif_output.imgheader - old_data;
if (offset && *offset) {
/* Pad to a given offset */
if (bif_output.data_len > *offset) {
printf("Can not pad to offset %zx\n", *offset);
return -1;
}
bif_output.data_len = *offset;
}
new_size = ROUND(bif_output.data_len + len, 64);
new_data = realloc(bif_output.data, new_size);
memcpy(new_data + bif_output.data_len, data, len);
if (offset)
*offset = bif_output.data_len;
bif_output.data = new_data;
bif_output.data_len = new_size;
/* Readjust internal pointers */
if (bif_output.header)
bif_output.header = new_data + header_off;
if (bif_output.last_part)
bif_output.last_part = new_data + last_part_off;
if (bif_output.imgheader)
bif_output.imgheader = new_data + imgheader_off;
return 0;
+}
+static int bif_init(void) +{
struct zynqmp_header header = { { 0 } };
int r;
zynqmpimage_default_header(&header);
r = bif_add_blob(&header, sizeof(header), NULL);
if (r)
return r;
bif_output.header = (void *)bif_output.data;
return 0;
+}
+static int bif_add_pmufw(struct bif_entry *bf, const char *data, size_t len) +{
int r;
if (bif_output.header->image_offset) {
printf("PMUFW expected before bootloader in your .bif file!\n");
return -1;
}
r = bif_add_blob(data, len, &bf->offset);
if (r)
return r;
len = ROUND(len, 64);
bif_output.header->pfw_image_length = cpu_to_le32(len);
bif_output.header->total_pfw_image_length = cpu_to_le32(len);
bif_output.header->image_offset = cpu_to_le32(bf->offset);
return 0;
+}
+static int bif_add_part(struct bif_entry *bf, const char *data, size_t len) +{
size_t parthdr_offset = 0;
struct partition_header parthdr = {
.len_enc = cpu_to_le32(len / 4),
.len_unenc = cpu_to_le32(len / 4),
.len = cpu_to_le32(len / 4),
.entry_point = cpu_to_le64(bf->entry),
.load_address = cpu_to_le64(bf->load),
};
int r;
uint32_t csum;
if (bf->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE))
return bif_add_pmufw(bf, data, len);
r = bif_add_blob(data, len, &bf->offset);
if (r)
return r;
parthdr.offset = cpu_to_le32(bf->offset / 4);
if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) {
if (bif_output.last_part) {
printf("ERROR: Bootloader expected before others\n");
return -1;
}
parthdr.offset = cpu_to_le32(bif_output.header->image_offset);
parthdr.len = cpu_to_le32((bf->offset + len -
bif_output.header->image_offset) / 4);
parthdr.len_enc = parthdr.len;
parthdr.len_unenc = parthdr.len;
}
/* Normalize EL */
bf->exp_lvl = bf->exp_lvl ? bf->exp_lvl - 1 : 3;
parthdr.attributes |= bf->exp_lvl << PART_ATTR_TARGET_EL_SHIFT;
parthdr.attributes |= bf->dest_dev;
parthdr.attributes |= bf->dest_cpu;
if (bf->flags & (1ULL << BIF_FLAG_TZ))
parthdr.attributes |= PART_ATTR_TZ_SECURE;
if (bf->flags & (1ULL << BIF_FLAG_PART_OWNER_UBOOT))
parthdr.attributes |= PART_ATTR_PART_OWNER_UBOOT;
switch (bf->dest_cpu) {
case PART_ATTR_DEST_CPU_NONE:
case PART_ATTR_DEST_CPU_A53_0:
case PART_ATTR_DEST_CPU_A53_1:
case PART_ATTR_DEST_CPU_A53_2:
case PART_ATTR_DEST_CPU_A53_3:
if (bf->flags & (1ULL << BIF_FLAG_AARCH32))
parthdr.attributes |= PART_ATTR_A53_EXEC_AARCH32;
}
csum = zynqmp_csum(&parthdr, &parthdr.checksum);
parthdr.checksum = cpu_to_le32(csum);
r = bif_add_blob(&parthdr, sizeof(parthdr), &parthdr_offset);
if (r)
return r;
/* Add image header table if not there yet */
if (!bif_output.imgheader) {
size_t imghdr_off = 0;
struct image_header_table imghdr = {
.version = cpu_to_le32(0x01020000),
.nr_parts = 0,
};
r = bif_add_blob(&imghdr, sizeof(imghdr), &imghdr_off);
if (r)
return r;
bif_output.header->image_header_table_offset = imghdr_off;
bif_output.imgheader = (void *)(bif_output.data + imghdr_off);
}
bif_output.imgheader->nr_parts = cpu_to_le32(le32_to_cpu(
bif_output.imgheader->nr_parts) + 1);
/* Link to this partition header */
if (bif_output.last_part) {
bif_output.last_part->next_partition_offset =
cpu_to_le32(parthdr_offset / 4);
/* Recalc checksum of last_part */
csum = zynqmp_csum(bif_output.last_part,
&bif_output.last_part->checksum);
bif_output.last_part->checksum = cpu_to_le32(csum);
} else {
bif_output.imgheader->partition_header_offset =
cpu_to_le32(parthdr_offset / 4);
}
bif_output.last_part = (void *)(bif_output.data + parthdr_offset);
if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) {
bif_output.header->image_load = cpu_to_le32(bf->load);
if (!bif_output.header->image_offset)
bif_output.header->image_offset =
cpu_to_le32(bf->offset);
bif_output.header->image_size = cpu_to_le32(len);
bif_output.header->image_stored_size = cpu_to_le32(len);
bif_output.header->image_attributes &= ~HEADER_CPU_SELECT_MASK;
switch (bf->dest_cpu) {
default:
case PART_ATTR_DEST_CPU_A53_0:
if (bf->flags & BIF_FLAG_AARCH32)
bif_output.header->image_attributes |=
HEADER_CPU_SELECT_A53_32BIT;
else
bif_output.header->image_attributes |=
HEADER_CPU_SELECT_A53_64BIT;
break;
case PART_ATTR_DEST_CPU_R5_0:
bif_output.header->image_attributes |=
HEADER_CPU_SELECT_R5_SINGLE;
break;
case PART_ATTR_DEST_CPU_R5_L:
bif_output.header->image_attributes |=
HEADER_CPU_SELECT_R5_DUAL;
break;
}
}
return 0;
+}
+/* Add .bit bitstream */ +static int bif_add_bit(struct bif_entry *bf) +{
char *bit = read_full_file(bf->filename, NULL);
char *bitbin;
uint8_t initial_header[] = { 0x00, 0x09, 0x0f, 0xf0, 0x0f, 0xf0, 0x0f,
0xf0, 0x0f, 0xf0, 0x00, 0x00, 0x01, 0x61 };
uint16_t len;
uint32_t bitlen;
int i;
if (!bit)
return -1;
/* Skip initial header */
if (memcmp(bit, initial_header, sizeof(initial_header)))
return -1;
bit += sizeof(initial_header);
/* Design name */
len = be16_to_cpu(*(uint16_t *)bit);
bit += sizeof(uint16_t);
debug("Design: %s\n", bit);
bit += len;
/* Device identifier */
if (*bit != 'b')
return -1;
bit++;
len = be16_to_cpu(*(uint16_t *)bit);
bit += sizeof(uint16_t);
debug("Device: %s\n", bit);
bit += len;
/* Date */
if (*bit != 'c')
return -1;
bit++;
len = be16_to_cpu(*(uint16_t *)bit);
bit += sizeof(uint16_t);
debug("Date: %s\n", bit);
bit += len;
/* Time */
if (*bit != 'd')
return -1;
bit++;
len = be16_to_cpu(*(uint16_t *)bit);
bit += sizeof(uint16_t);
debug("Time: %s\n", bit);
bit += len;
/* Bitstream length */
if (*bit != 'e')
return -1;
bit++;
bitlen = be32_to_cpu(*(uint32_t *)bit);
bit += sizeof(uint32_t);
bitbin = bit;
debug("Bitstream Length: 0x%x\n", bitlen);
for (i = 0; i < bitlen; i += sizeof(uint32_t)) {
uint32_t *bitbin32 = (uint32_t *)&bitbin[i];
*bitbin32 = __swab32(*bitbin32);
}
if (!bf->dest_dev)
bf->dest_dev = PART_ATTR_DEST_DEVICE_PL;
bf->load = 0xffffffff;
bf->entry = 0;
bf->flags |= 1ULL << BIF_FLAG_BIT_FILE;
return bif_add_part(bf, bit, bitlen);
+}
+/* Add .bin bitstream */ +static int bif_add_bin(struct bif_entry *bf) +{
size_t size;
char *bin = read_full_file(bf->filename, &size);
if (!bf->dest_dev)
bf->dest_dev = PART_ATTR_DEST_DEVICE_PS;
bf->flags |= 1ULL << BIF_FLAG_BIN_FILE;
return bif_add_part(bf, bin, size);
+}
+/* Add elf file */ +static char *elf2flat64(char *elf, size_t *flat_size, size_t *load_addr) +{
Elf64_Ehdr *ehdr;
Elf64_Shdr *shdr;
size_t min_addr = -1, max_addr = 0;
char *flat;
int i;
ehdr = (void *)elf;
shdr = (void *)(elf + le64_to_cpu(ehdr->e_shoff));
/* Look for smallest / biggest address */
for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++, shdr++) {
if (!shdr->sh_size || !shdr->sh_addr ||
!(shdr->sh_flags & SHF_ALLOC) ||
(shdr->sh_type == SHT_NOBITS))
continue;
if (le64_to_cpu(shdr->sh_addr) < min_addr)
min_addr = le64_to_cpu(shdr->sh_addr);
if ((le64_to_cpu(shdr->sh_addr) + le64_to_cpu(shdr->sh_size)) >
max_addr)
max_addr = le64_to_cpu(shdr->sh_addr) +
le64_to_cpu(shdr->sh_size);
}
*load_addr = min_addr;
*flat_size = max_addr - min_addr;
flat = calloc(1, *flat_size);
if (!flat)
return NULL;
shdr = (void *)(elf + le64_to_cpu(ehdr->e_shoff));
for (i = 0; i < le64_to_cpu(ehdr->e_shnum); i++, shdr++) {
char *dst = flat + le64_to_cpu(shdr->sh_addr) - min_addr;
char *src = elf + le64_to_cpu(shdr->sh_offset);
if (!shdr->sh_size || !shdr->sh_addr ||
!(shdr->sh_flags & SHF_ALLOC))
continue;
if (shdr->sh_type != SHT_NOBITS)
memcpy(dst, src, le64_to_cpu(shdr->sh_size));
}
return flat;
+}
+static char *elf2flat32(char *elf, size_t *flat_size, size_t *load_addr) +{
Elf32_Ehdr *ehdr;
Elf32_Shdr *shdr;
size_t min_addr = -1, max_addr = 0;
char *flat;
int i;
ehdr = (void *)elf;
shdr = (void *)(elf + le32_to_cpu(ehdr->e_shoff));
/* Look for smallest / biggest address */
for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++, shdr++) {
if (!shdr->sh_size || !shdr->sh_addr ||
!(shdr->sh_flags & SHF_ALLOC) ||
(shdr->sh_type == SHT_NOBITS))
continue;
if (le32_to_cpu(shdr->sh_addr) < min_addr)
min_addr = le32_to_cpu(shdr->sh_addr);
if ((le32_to_cpu(shdr->sh_addr) + le32_to_cpu(shdr->sh_size)) >
max_addr)
max_addr = le32_to_cpu(shdr->sh_addr) +
le32_to_cpu(shdr->sh_size);
}
*load_addr = min_addr;
*flat_size = max_addr - min_addr;
flat = calloc(1, *flat_size);
if (!flat)
return NULL;
shdr = (void *)(elf + le32_to_cpu(ehdr->e_shoff));
for (i = 0; i < le32_to_cpu(ehdr->e_shnum); i++, shdr++) {
char *dst = flat + le32_to_cpu(shdr->sh_addr) - min_addr;
char *src = elf + le32_to_cpu(shdr->sh_offset);
if (!shdr->sh_size || !shdr->sh_addr ||
!(shdr->sh_flags & SHF_ALLOC))
continue;
if (shdr->sh_type != SHT_NOBITS)
memcpy(dst, src, le32_to_cpu(shdr->sh_size));
}
return flat;
+}
+static int bif_add_elf(struct bif_entry *bf) +{
size_t size;
size_t elf_size;
char *elf;
char *flat;
size_t load_addr;
Elf32_Ehdr *ehdr32;
Elf64_Ehdr *ehdr64;
elf = read_full_file(bf->filename, &elf_size);
if (!elf)
return -1;
ehdr32 = (void *)elf;
ehdr64 = (void *)elf;
switch (ehdr32->e_ident[EI_CLASS]) {
case ELFCLASS32:
flat = elf2flat32(elf, &size, &load_addr);
bf->entry = le32_to_cpu(ehdr32->e_entry);
bf->flags |= 1ULL << BIF_FLAG_AARCH32;
break;
case ELFCLASS64:
flat = elf2flat64(elf, &size, &load_addr);
bf->entry = le64_to_cpu(ehdr64->e_entry);
break;
default:
printf("Unknown ELF class: %d\n", ehdr32->e_ident[EI_CLASS]);
return -1;
}
if (!flat)
return -1;
bf->load = load_addr;
if (!bf->dest_dev)
bf->dest_dev = PART_ATTR_DEST_DEVICE_PS;
bf->flags |= 1ULL << BIF_FLAG_ELF_FILE;
return bif_add_part(bf, flat, size);
+}
+static const struct bif_file_type bif_file_types[] = {
{
.name = "bitstream (.bit)",
.header = 0x00090ff0,
.add = bif_add_bit,
},
{
.name = "ELF",
.header = 0x7f454c46,
.add = bif_add_elf,
},
/* Anything else is a .bin file */
{
.name = ".bin",
.add = bif_add_bin,
},
+};
+static int bif_fsbl_config(struct bif_entry *fsbl_config,
struct bif_entry *entries, int nr_entries)
+{
int i;
int config_set = 0;
struct {
const char *name;
uint64_t flags;
uint64_t dest_cpu;
} configs[] = {
{ .name = "a5x_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 },
{ .name = "a53_x64", .dest_cpu = PART_ATTR_DEST_CPU_A53_0 },
{ .name = "a5x_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0,
.flags = 1ULL << BIF_FLAG_AARCH32 },
{ .name = "a53_x32", .dest_cpu = PART_ATTR_DEST_CPU_A53_0,
.flags = 1ULL << BIF_FLAG_AARCH32 },
{ .name = "r5_single", .dest_cpu = PART_ATTR_DEST_CPU_R5_0 },
{ .name = "r5_dual", .dest_cpu = PART_ATTR_DEST_CPU_R5_L },
};
/* Set target CPU of bootloader entry */
for (i = 0; i < nr_entries; i++) {
struct bif_entry *b = &entries[i];
const char *config_attr = fsbl_config->filename;
int j;
if (!(b->flags & (1ULL << BIF_FLAG_BOOTLOADER)))
continue;
for (j = 0; j < ARRAY_SIZE(configs); j++) {
if (!strncmp(config_attr, configs[j].name,
strlen(configs[j].name))) {
b->dest_cpu = configs[j].dest_cpu;
b->flags |= configs[j].flags;
config_set = 1;
}
}
if (!config_set) {
printf("ERROR: Unsupported fsbl_config: %s\n",
config_attr);
return -1;
}
}
if (!config_set) {
printf("ERROR: fsbl_config w/o bootloader\n");
return -1;
}
return 0;
+}
+static const struct bif_flags *find_flag(char *str) +{
const struct bif_flags *bf;
int i;
for (i = 0; i < ARRAY_SIZE(bif_flags); i++) {
bf = &bif_flags[i];
if (!strncmp(bf->name, str, strlen(bf->name)))
return bf;
}
printf("ERROR: Flag '%s' not found\n", str);
return NULL;
+}
+static int bif_open_file(struct bif_entry *entry) +{
int fd = open(entry->filename, O_RDONLY);
if (fd < 0)
printf("Error opening file %s\n", entry->filename);
return fd;
+}
+static const struct bif_file_type *get_file_type(struct bif_entry *entry) +{
int fd = bif_open_file(entry);
uint32_t header;
int i;
if (fd < 0)
return NULL;
if (read(fd, &header, sizeof(header)) != sizeof(header)) {
printf("Error reading file %s", entry->filename);
return NULL;
}
close(fd);
for (i = 0; i < ARRAY_SIZE(bif_file_types); i++) {
const struct bif_file_type *type = &bif_file_types[i];
if (!type->header)
return type;
if (type->header == be32_to_cpu(header))
return type;
}
return NULL;
+}
+#define NEXT_CHAR(str, chr) ({ \
char *_n = strchr(str, chr); \
if (!_n) \
goto err; \
_n; \
+})
+static char *skip_whitespace(char *str) +{
while (*str == ' ' || *str == '\t')
str++;
return str;
+}
+int zynqmpbif_copy_image(int outfd, struct image_tool_params *mparams) +{
char *bif, *bifp, *bifpn;
char *line;
struct bif_entry entries[32] = { { 0 } };
int nr_entries = 0;
struct bif_entry *entry = entries;
size_t len;
int i;
uint32_t csum;
int bldr = -1;
bif_init();
/* Read .bif input file */
bif = read_full_file(mparams->datafile, NULL);
if (!bif)
goto err;
/* Interpret .bif file */
bifp = bif;
/* A bif description starts with a { section */
bifp = NEXT_CHAR(bifp, '{') + 1;
/* Read every line */
while (1) {
bifpn = NEXT_CHAR(bifp, '\n');
if (bifpn[-1] == '\r')
bifpn[-1] = '\0';
*bifpn = '\0';
bifpn++;
line = bifp;
line = skip_whitespace(line);
/* Attributes? */
if (*line == '[') {
line++;
while (1) {
const struct bif_flags *bf;
line = skip_whitespace(line);
bf = find_flag(line);
if (!bf)
goto err;
line += strlen(bf->name);
if (bf->parse)
line = bf->parse(line, entry);
else
entry->flags |= 1ULL << bf->flag;
if (!line)
goto err;
/* Go to next attribute or quit */
if (*line == ']') {
line++;
break;
}
if (*line == ',')
line++;
}
}
/* End of image description */
if (*line == '}')
break;
if (*line) {
line = skip_whitespace(line);
entry->filename = line;
nr_entries++;
entry++;
}
/* Use next line */
bifp = bifpn;
}
for (i = 0; i < nr_entries; i++) {
debug("Entry flags=%#lx name=%s\n", entries[i].flags,
entries[i].filename);
}
/*
* Some entries are actually configuration option for other ones,
* let's apply them in an intermediate step.
*/
for (i = 0; i < nr_entries; i++) {
struct bif_entry *entry = &entries[i];
if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG))
if (bif_fsbl_config(entry, entries, nr_entries))
goto err;
}
/* Make sure PMUFW comes before bootloader */
for (i = 0; i < nr_entries; i++) {
struct bif_entry *entry = &entries[i];
if (entry->flags & (1ULL << BIF_FLAG_BOOTLOADER))
bldr = i;
if (entry->flags & (1ULL << BIF_FLAG_PMUFW_IMAGE)) {
if (bldr >= 0) {
struct bif_entry tmp = *entry;
*entry = entries[bldr];
entries[bldr] = tmp;
}
}
}
for (i = 0; i < nr_entries; i++) {
struct bif_entry *entry = &entries[i];
const struct bif_file_type *type;
int r;
if (entry->flags & (1ULL << BIF_FLAG_FSBL_CONFIG))
continue;
type = get_file_type(entry);
if (!type)
goto err;
debug("type=%s file=%s\n", type->name, entry->filename);
r = type->add(entry);
if (r)
goto err;
}
/* Calculate checksums */
csum = zynqmp_csum(&bif_output.header->width_detection,
&bif_output.header->checksum);
bif_output.header->checksum = cpu_to_le32(csum);
if (bif_output.imgheader) {
csum = zynqmp_csum(bif_output.imgheader,
&bif_output.imgheader->checksum);
bif_output.imgheader->checksum = cpu_to_le32(csum);
}
/* Write headers and components */
if (lseek(outfd, 0, SEEK_SET) != 0)
goto err;
len = bif_output.data_len;
bifp = bif_output.data;
while (len) {
int r;
r = write(outfd, bifp, len);
if (r < 0)
goto err;
len -= r;
bifp += r;
}
return 0;
+err:
fprintf(stderr, "Error: Failed to create image.\n");
return -1;
+}
+/* Needs to be stubbed out so we can print after creation */ +static void zynqmpbif_set_header(void *ptr, struct stat *sbuf, int ifd,
struct image_tool_params *params)
+{ +}
+static struct zynqmp_header zynqmpimage_header;
+U_BOOT_IMAGE_TYPE(
zynqmpbif,
"Xilinx ZynqMP Boot Image support (bif)",
sizeof(struct zynqmp_header),
(void *)&zynqmpimage_header,
zynqmpbif_check_params,
NULL,
zynqmpimage_print_header,
zynqmpbif_set_header,
NULL,
zynqmpbif_check_image_types,
NULL,
NULL
+); diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index 3bd23b9bf8..288816d6cd 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -87,7 +87,7 @@ static uint32_t zynqmpimage_checksum(struct zynqmp_header *ptr) return cpu_to_le32(checksum); }
-static void zynqmpimage_default_header(struct zynqmp_header *ptr) +void zynqmpimage_default_header(struct zynqmp_header *ptr) { int i;
@@ -210,7 +210,7 @@ static void print_partition(const void *ptr, const struct partition_header *ph) printf(" Checksum : 0x%08x\n", le32_to_cpu(ph->checksum)); }
-static void zynqmpimage_print_header(const void *ptr) +void zynqmpimage_print_header(const void *ptr) { struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; int i; diff --git a/tools/zynqmpimage.h b/tools/zynqmpimage.h index f3b5c195ad..7a57681709 100644 --- a/tools/zynqmpimage.h +++ b/tools/zynqmpimage.h @@ -19,7 +19,11 @@ #define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff)) #define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566)) #define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58)) +#define HEADER_CPU_SELECT_MASK (0x3 << 10) +#define HEADER_CPU_SELECT_R5_SINGLE (0x0 << 10) +#define HEADER_CPU_SELECT_A53_32BIT (0x1 << 10) #define HEADER_CPU_SELECT_A53_64BIT (0x2 << 10) +#define HEADER_CPU_SELECT_R5_DUAL (0x3 << 10)
enum { ENCRYPTION_EFUSE = 0xa5c3c5a3, @@ -129,4 +133,7 @@ struct zynqmp_header { uint32_t __reserved4[66]; /* 0x9c0 */ };
+void zynqmpimage_default_header(struct zynqmp_header *ptr); +void zynqmpimage_print_header(const void *ptr);
#endif /* _ZYNQMPIMAGE_H_ */
2.12.3
U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot