From patchwork Fri Jun 1 16:46:03 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Vicente Bergas X-Patchwork-Id: 924244 X-Patchwork-Delegate: philipp.tomsich@theobroma-systems.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="rDCZILVG"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 40y9nn53fXz9s1p for ; Sat, 2 Jun 2018 03:10:37 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 607D9C21DFD; Fri, 1 Jun 2018 17:09:48 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=FREEMAIL_FROM, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id AD553C21C29; Fri, 1 Jun 2018 17:09:27 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id E52B5C21C93; Fri, 1 Jun 2018 16:46:44 +0000 (UTC) Received: from mail-lf0-f43.google.com (mail-lf0-f43.google.com [209.85.215.43]) by lists.denx.de (Postfix) with ESMTPS id 5BE13C21C29 for ; Fri, 1 Jun 2018 16:46:44 +0000 (UTC) Received: by mail-lf0-f43.google.com with SMTP id 36-v6so13806257lfr.11 for ; Fri, 01 Jun 2018 09:46:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=fWurR6Qm5TodphnSgHRGb24Cv2ypLYG2WCFea71nx3A=; b=rDCZILVGGJmLDFAIVn4xfVtQriiNt2GfVHuibX58fsWR6DHMPe8KjixPMijyE3ZnRm moWkdL/iuo1/eVEm45mdmNNsOHVz/gqWJRQNDog5dAzUYl5LPuq1+akbPNyclP53jpwI ydv3P2lsxTNjC/WlLsqT/ViS6ObIj3DkrIpADkkMtFr8htEG6cNKPz2O0+Y3kZ9yHSXS GolWLuAA1uIgmt+tGLWYTdzli6xaLzVE6FFB5C5XT9ofpwYPDL9546c0Otg8Km77z3Bg z4J2h5bKc7Og4sk9lSyEU63oEX1ZNZI++yTjY+zIuoe5UDqY6o9C4OYdRnThF6uY5VX3 cDkg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=fWurR6Qm5TodphnSgHRGb24Cv2ypLYG2WCFea71nx3A=; b=aZB2UOVlb3pOWJKFIwHePqRwnsRNpH6ax5VXexFigPlVm2C6oPGUeVDZfvypchHS+5 CLD06dwljpOxNZpA/GwOmuvS0d3wJwRKNDU0Tqpi1NT7vqgLRv5pGqHNSsEBy6+G3yX+ pMktgaY2/opgjjT9t+jaLdP0RHHlPiJfzwZOgxl8CCgGu0y7/ZQRKnG774ZwY0Xkd0JX OmW8+udMMc42gmmIzbOG7/5Lxx0R2vU8clVGMheJRtc58wGC/jIYwBUm7I4TxjZ2d/J6 edE2BjARMfBlmWOIyI+WZgoGEthlseJoynvx0spfL1fggz3iSgjrgneVcFyCD6o6hkRz cShg== X-Gm-Message-State: APt69E3ruAwD+Fm7yco3c4WS7+oiQ46VCkXetpa8G3gOM+MxSJahPhI9 0oeD2iyhGH2CH+ug2JH3ImQ= X-Google-Smtp-Source: ADUXVKLTi9ntxF2g15l9DZncnKLf/jLbFc6k0JDs0fqoax0YFFdcZzH4uxvOXvnLmQ1FMIxEMFF1kw== X-Received: by 2002:a2e:1710:: with SMTP id l16-v6mr2214614lje.74.1527871603839; Fri, 01 Jun 2018 09:46:43 -0700 (PDT) Received: from localhost.localdomain (80-198-72-241-cable.dk.customer.tdc.net. [80.198.72.241]) by smtp.gmail.com with ESMTPSA id w62-v6sm2299612lff.57.2018.06.01.09.46.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 01 Jun 2018 09:46:43 -0700 (PDT) From: Vicente Bergas X-Google-Original-From: Vicente Bergas To: philipp.tomsich@theobroma-systems.com, kever.yang@rock-chips.com, u-boot@lists.denx.de Date: Fri, 1 Jun 2018 18:46:03 +0200 Message-Id: <20180601164606.8387-2-vicencb@users.noreply.github.com> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20180601164606.8387-1-vicencb@users.noreply.github.com> References: <20180601164606.8387-1-vicencb@users.noreply.github.com> X-Mailman-Approved-At: Fri, 01 Jun 2018 17:09:25 +0000 Cc: Vicente Bergas Subject: [U-Boot] [PATCH 1/4] add make_fit_atf in tools X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Vicente Bergas make_fit_atf generates an .its file based on U-Boot and ATF .elf files. It also extracts all loadable sections from ATF. It tries to somewhat mimic the behaviour of arch/arm/mach-rockchip/make_fit_atf.py Signed-off-by: Vicente Bergas --- tools/Makefile | 2 + tools/make_fit_atf.c | 360 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 362 insertions(+) create mode 100644 tools/make_fit_atf.c diff --git a/tools/Makefile b/tools/Makefile index 5dd33ed4d5..a282f04f63 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -56,6 +56,8 @@ mkenvimage-objs := mkenvimage.o os_support.o lib/crc32.o hostprogs-y += dumpimage mkimage hostprogs-$(CONFIG_FIT_SIGNATURE) += fit_info fit_check_sign +hostprogs-$(CONFIG_SPL_ATF) += make_fit_atf + hostprogs-$(CONFIG_CMD_BOOTEFI_SELFTEST) += file2include FIT_SIG_OBJS-$(CONFIG_FIT_SIGNATURE) := common/image-sig.o diff --git a/tools/make_fit_atf.c b/tools/make_fit_atf.c new file mode 100644 index 0000000000..91101aaf8a --- /dev/null +++ b/tools/make_fit_atf.c @@ -0,0 +1,360 @@ +// SPDX-License-Identifier: 0BSD + +#include +#include +#include +#include +#include + +static char const *dtb_basename (char const *path) { + enum { FILE_SEPARATOR = '/' }; + size_t ln = strlen(path); + if (!ln || path[ln - 1] == FILE_SEPARATOR) { + fprintf(stderr, "dtb file name error '%s'.\n", path); + return NULL; + } + char const *base = path + ln - 1; + while (base > path && *base != FILE_SEPARATOR) --base; + if (*base == FILE_SEPARATOR) ++base; + return base; +} + +/* + http://www.sco.com/developers/gabi/latest/ch4.intro.html + http://www.sco.com/developers/gabi/latest/ch4.eheader.html + http://www.sco.com/developers/gabi/latest/ch4.sheader.html + http://www.sco.com/developers/gabi/latest/ch5.pheader.html +*/ +enum { EI_MAG0, EI_MAG1, EI_MAG2, EI_MAG3, EI_CLASS, EI_DATA, EI_VERSION, EI_NIDENT = 16 }; +enum { ELFMAG0 = 0x7F, ELFMAG1 = 'E', ELFMAG2 = 'L', ELFMAG3 = 'F' }; +enum { ELFCLASSNONE, ELFCLASS32, ELFCLASS64 }; +enum { ELFDATANONE, ELFDATA2LSB, ELFDATA2MSB }; +enum { ET_NONE, ET_REL, ET_EXEC, ET_DYN, ET_CORE }; +enum { EM_NONE, EM_ARM = 40, EM_AARCH64 = 183 }; +enum { EV_NONE, EV_CURRENT }; +enum { PT_NULL, PT_LOAD, PT_DYNAMIC, PT_INTERP, PT_NOTE, PT_SHLIB, PT_PHDR, PT_TLS }; +enum { SHT_NULL, SHT_PROGBITS, SHT_SYMTAB, SHT_STRTAB, SHT_RELA, SHT_HASH, SHT_DYNAMIC, SHT_NOTE, SHT_NOBITS }; +enum { SHF_ALLOC = 2 }; +typedef struct { + uint8_t e_ident[EI_NIDENT]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +} Elf64_Ehdr; +typedef struct { + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +} Elf64_Phdr; +typedef struct { + uint32_t sh_name; + uint32_t sh_type; + uint64_t sh_flags; + uint64_t sh_addr; + uint64_t sh_offset; + uint64_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint64_t sh_addralign; + uint64_t sh_entsize; +} Elf64_Shdr; + +static FILE *elf_open(char const *file_name, Elf64_Ehdr *eh) { + FILE *f = fopen(file_name, "rb"); + if (!f) { + fprintf(stderr, "Error openning '%s': %s.\n", file_name, strerror(errno)); + return 0; + } + if (fread(eh, EI_NIDENT, 1, f) != 1) { + if (feof(f)) { + fprintf(stderr, "Not ELF file.\n"); + return 0; + } + fprintf(stderr, "Error reading '%s'.\n", file_name); + return 0; + } + if ( + eh->e_ident[EI_MAG0] != ELFMAG0 || + eh->e_ident[EI_MAG1] != ELFMAG1 || + eh->e_ident[EI_MAG2] != ELFMAG2 || + eh->e_ident[EI_MAG3] != ELFMAG3 + ) { + fprintf(stderr, "Not ELF file.\n"); + return 0; + } + if ( + eh->e_ident[EI_CLASS] != ELFCLASS64 || + eh->e_ident[EI_DATA] != ELFDATA2LSB || + eh->e_ident[EI_VERSION] != EV_CURRENT + ) { + fprintf(stderr, "Only version %u 64-bit little-endian ELF files supported.\n", EV_CURRENT); + return 0; + } + if (!*(uint8_t *)&(uint32_t){1}) { + fprintf(stderr, "Only little-endian hosts supported.\n"); + return 0; + } + if (fread(((void *)eh) + EI_NIDENT, sizeof(*eh) - EI_NIDENT, 1, f) != 1) { + fprintf(stderr, "Error reading '%s'.\n", file_name); + return 0; + } + + if ( + eh->e_version != EV_CURRENT || + eh->e_ehsize != sizeof(Elf64_Ehdr) || + eh->e_phentsize != sizeof(Elf64_Phdr) || + eh->e_shentsize != sizeof(Elf64_Shdr) + ) { + fprintf(stderr, "Unexpected ELF file.\n"); + return 0; + } + if (eh->e_machine != EM_AARCH64) { + fprintf(stderr, "Only arm64 supported.\n"); + return 0; + } + return f; +} + +enum { GOTO_EH, GOTO_PH, GOTO_SH }; +static int elf_goto(char const *file_name, FILE *elf, Elf64_Ehdr const *eh, unsigned where) { + uint64_t seek = 0; + switch (where) { + case GOTO_EH: break; + case GOTO_PH: seek = eh->e_phoff; break; + case GOTO_SH: seek = eh->e_shoff; break; + } + if (fseek(elf, seek, SEEK_SET)) { + fprintf(stderr, "Error seeking '%s'.\n", file_name); + return -1; + } + return 0; +} + +static int elf_next_ph(char const *file_name, FILE *elf, Elf64_Phdr *ph) { + if (fread(ph, sizeof(Elf64_Phdr), 1, elf) != 1) { + fprintf(stderr, "Error reading '%s'.\n", file_name); + return -1; + } + return 0; +} + +static int elf_next_sh(char const *file_name, FILE *elf, Elf64_Shdr *sh) { + if (fread(sh, sizeof(Elf64_Shdr), 1, elf) != 1) { + fprintf(stderr, "Error reading '%s'.\n", file_name); + return -1; + } + return 0; +} + +int main(int argc, char **argv) { + Elf64_Ehdr eh; + Elf64_Phdr ph; + Elf64_Shdr sh; + FILE *fi; + FILE *fo = stdout; + char *uboot = "u-boot"; + char *bl31 = "bl31.elf"; + void *buffer = 0; + size_t buffer_len = 0; + uint64_t addr; + int cnt; + + if (!argc) { return -1; } + --argc; ++argv; + + while (argc) { + if (argv[0][0] != '-') { break; } + char opt = argv[0][1]; + --argc; ++argv; + if (argv[-1][2]) { +err_option: + fprintf(stderr, "Error with option '%s'.\n", argv[-1]); +usage: + fprintf(stderr, "make_fit_atf [-h] [-o out_file] [-u u_boot_file] [-b bl31_file] dtb_file[s]\n"); + return -1; + } + switch (opt) { + default : goto err_option; + case 'h': goto usage; + case 'u': uboot = argv[0]; break; + case 'b': bl31 = argv[0]; break; + case 'o': + if (fo != stdout) { + fprintf(stderr, "Maximum one -o option.\n"); + return -1; + } + fo = fopen(argv[0], "w"); + if (!fo) { + fprintf(stderr, "Could not open '%s' for writing: %s.\n", argv[0], strerror(errno)); + return -1; + } + } + --argc; ++argv; + } + + fi = elf_open(uboot, &eh); + if (!fi) { return -1; } + if (elf_goto(uboot, fi, &eh, GOTO_PH)) { return -1; } + cnt = 0; + for (unsigned i = 0; i < eh.e_phnum; ++i) { + if (elf_next_ph(uboot, fi, &ph)) { return -1; } + if (ph.p_type != PT_LOAD) { continue; } + if (ph.p_vaddr != ph.p_paddr) { + fprintf(stderr, "Virtual address not supported.\n"); + return -1; + } + addr = ph.p_vaddr; + ++cnt; + } + if (cnt != 1) { + fprintf(stderr, "Only one loadable segment expected.\n"); + return -1; + } + fclose(fi); + + fprintf(fo, + "/dts-v1/;\n" + "\n" + "/ {\n" + " description = \"Configuration to load ATF before U-Boot\";\n" + " #address-cells = <1>;\n" + "\n" + " images {\n" + " uboot {\n" + " description = \"U-Boot\";\n" + " data = /incbin/(\"u-boot-nodtb.bin\");\n" + " type = \"standalone\";\n" + " os = \"U-Boot\";\n" + " arch = \"arm64\";\n" + " compression = \"none\";\n" + " load = <0x%08lX>;\n" + " };\n" + , addr + ); + + fi = elf_open(bl31, &eh); + if (!fi) { return -1; } + if (elf_goto(bl31, fi, &eh, GOTO_SH)) { return -1; } + cnt = 0; + int fw_entry = -1; + for (unsigned i = 0; i < eh.e_shnum; ++i) { + if (elf_next_sh(bl31, fi, &sh)) { return -1; } + if (sh.sh_type != SHT_PROGBITS || !(sh.sh_flags & SHF_ALLOC)) { continue; } + ++cnt; + fprintf(fo, + " atf%u {\n" + " description = \"ARM Trusted Firmware\";\n" + " data = /incbin/(\"bl31_0x%08lX.bin\");\n" + " type = \"firmware\";\n" + " arch = \"arm64\";\n" + " os = \"arm-trusted-firmware\";\n" + " compression = \"none\";\n" + " load = <0x%08lX>;\n" + , cnt + , sh.sh_addr + , sh.sh_addr + ); + if (sh.sh_addr <= eh.e_entry && eh.e_entry < sh.sh_addr + sh.sh_size) { + fprintf(fo, " entry = <0x%08lX>;\n", eh.e_entry); + fw_entry = cnt; + } + fprintf(fo, " };\n"); + + if (1) { + if (buffer_len < sh.sh_size) { + if (buffer_len) { free(buffer); } + buffer_len = sh.sh_size; + buffer = malloc(buffer_len); + if (!buffer) { + fprintf(stderr, "%s.\n", strerror(errno)); + return -1; + } + } + long current = ftell(fi); + int sk = fseek(fi, sh.sh_offset, SEEK_SET); + size_t ln = fread(buffer, sh.sh_size, 1, fi); + int sk2 = fseek(fi, current, SEEK_SET); + if (current < 0 || sk || ln != 1 || sk2) { + fprintf(stderr, "Could not read '%s': %s.\n", bl31, strerror(errno)); + return -1; + } + + char fname[32]; + sprintf(fname, "bl31_0x%08lX.bin", sh.sh_addr); + FILE *f = fopen(fname, "wb"); + if (f) { + ln = fwrite(buffer, sh.sh_size, 1, f); + fclose(f); + } + if (!f || ln != 1) { + fprintf(stderr, "Could not write to '%s': %s.\n", fname, strerror(errno)); + return -1; + } + } + } + fclose(fi); + + for (int j = 0; j < argc; ++j) { + fprintf(fo, + " fdt%d {\n" + " description = \"%s\";\n" + " data = /incbin/(\"%s\");\n" + " type = \"flat_dt\";\n" + " compression = \"none\";\n" + " };\n" + , j + 1 + , dtb_basename(argv[j]) + , argv[j] + ); + } + fprintf(fo, " };\n" ); + + if (argc) { + fprintf(fo, + " configurations {\n" + " default = \"config1\";\n" + ); + for (int j = 0; j < argc; ++j) { + fprintf(fo, + " config%d {\n" + " description = \"%s\";\n" + , j + 1 + , dtb_basename(argv[j]) + ); + if (fw_entry >= 0) { + fprintf(fo, " firmware = \"atf%d\";\n", fw_entry); + } + fprintf(fo, " loadables = \"uboot\""); + for (int i = 1; i <= cnt; ++i) { + if (i != fw_entry) { + fprintf(fo, ",\"atf%u\"", i); + } + } + fprintf(fo, + ";\n" + " fdt = \"fdt%u\";\n" + " };\n" + , j + 1 + ); + } + fprintf(fo, " };\n"); + } + + fprintf(fo, "};\n"); + return 0; +}