/* * Copyright (C) 2018 Alexander Graf * * SPDX-License-Identifier: GPL-2.0+ */ #include "imagetool.h" #include "mkimage.h" #include "zynqmpimage.h" #include #include 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 );