u-boot/tools/zynqmpbif.c
Michael Tretter 16c78cba92 tools: zynqmpimage: round up partition size
The FSBL copies "Total Partition Word Length" * 4 bytes from the boot.bin,
which implies that the partition size is 4 byte aligned. When writing the
partition, mkimage calculates "Total Partition Word Length" by dividing
the size by 4. This implicitly cuts unaligned bytes at the end of the
added binary.

Instead of rounding down, the size must be round up to 4 bytes and the
binary padded accordingly.

Signed-off-by: Michael Tretter <m.tretter@pengutronix.de>
Reviewed-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
2019-01-24 10:03:42 +01:00

1017 lines
22 KiB
C

/*
* 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;
size_t len_padded = ROUND(len, 4);
struct partition_header parthdr = {
.len_enc = cpu_to_le32(len_padded / 4),
.len_unenc = cpu_to_le32(len_padded / 4),
.len = cpu_to_le32(len_padded / 4),
.entry_point = cpu_to_le64(bf->entry),
.load_address = cpu_to_le64(bf->load),
};
int r;
uint32_t csum;
if (len < len_padded) {
char *newdata = malloc(len_padded);
memcpy(newdata, data, len);
memset(newdata + len, 0, len_padded - len);
data = newdata;
}
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
);