From patchwork Thu Apr 12 13:41:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Graf X-Patchwork-Id: 133277 Delivered-To: patch@linaro.org Received: by 10.46.84.29 with SMTP id i29csp1700961ljb; Thu, 12 Apr 2018 06:43:11 -0700 (PDT) X-Google-Smtp-Source: AIpwx480J+OTKKXcTt17r0U5VkEBwctkh9nEmk/1A4SujYU0hYhT1jvorGr2OxmxjD5iTk/vFGfU X-Received: by 10.80.177.81 with SMTP id l17mr15569654edd.65.1523540591439; Thu, 12 Apr 2018 06:43:11 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523540591; cv=none; d=google.com; s=arc-20160816; b=RfAB67i83g5bFfuxvvaVkv7vbVzHQJ2mwPD9y5H7+OwPQKQ7m8w8LJBtflNzG0Nv8p JBuad9i0jEmDOzQHF/n+ssrP+g/T/ZGc8Fx9iQKgigsUdWVotRKwPX41LLlVKkTJBFSi C4dWd56WbXylpvSzZzCENgivKlS5YQ4r30QyrxDNIX3hCYFFAf3m3uDW4OS3oUWmGXKP 5jVwSRxA7LI1ZHYd0DrlBeUGkht5S6umTROYxXad88jfQ4AEZcuGKzaLhUSsZ/4/u7e1 CcHEJMvVzgnxIlklt91xr4VlYDFnWZTKk7750s0nAt/yXCywXmc8efaLMTtRrItuAcFk DrrQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:arc-authentication-results; bh=IjXUPQdUKLobCKJbMqxa6iKsyIPuJiw0QTclAs1Isi8=; b=AxasGENHsVKVid79qoVMJoNNvtmNYNTL/6a4ywsknx6SqzGMrnSI/BsPu1XWV1WIJi Lrdc/1RBggRTxB4hzwE660LsDn581Z3usKF7U2MlbekJTQAhQnMXv8JJ+G7ztPZ1HCPe EgcZ22Co82PhAT4z7HsETuGsysS2xD4PNLA+kivVzp1oKwVpXh9fGFardyogL/E5MEeA U5T5+FAm6YwHRSNwTBuOcN0WbVLc4fyKs05EqZjMKpJSj5YvnVncSZmPheJFniUQVg+q xQmJnT+awHDrDMVIoXajwhkpv/cDEZU8Pl07ioh3a4XJkazVcPFVYKOzbKjsOwHftGx8 PvVQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id y9si691538edh.277.2018.04.12.06.43.11; Thu, 12 Apr 2018 06:43:11 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id F1A05C21C6A; Thu, 12 Apr 2018 13:42:26 +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=none 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 B9498C21DA2; Thu, 12 Apr 2018 13:42:03 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id 7FB4FC21C2C; Thu, 12 Apr 2018 13:42:01 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by lists.denx.de (Postfix) with ESMTPS id F3A49C21C2F for ; Thu, 12 Apr 2018 13:42:00 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 2AA4FAD16; Thu, 12 Apr 2018 13:42:00 +0000 (UTC) From: Alexander Graf To: u-boot@lists.denx.de Date: Thu, 12 Apr 2018 15:41:56 +0200 Message-Id: <20180412134158.69300-2-agraf@suse.de> X-Mailer: git-send-email 2.12.3 In-Reply-To: <20180412134158.69300-1-agraf@suse.de> References: <20180412134158.69300-1-agraf@suse.de> Subject: [U-Boot] [PATCH v2 1/3] tools: zynqmpimage: Add partition read support 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" The zynqmp image format has support for inline partitions which are used by FSBL to describe payloads that are loaded by FSBL itself. While we can't create images that contain partitions (yet), we should still at least be able to examine them and show the user what's inside when we analyze an image created by bootgen. Signed-off-by: Alexander Graf --- v1 -> v2: - prettify defines - fix offset and size outputs - add u-boot as payload target - align CPU names with bif - add shift constants - add U-Boot as potential partition owner - mention documentation source - add HEADER_CPU_SELECT_A53_64BIT define --- tools/zynqmpimage.c | 174 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 172 insertions(+), 2 deletions(-) diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index a61fb17c40..8117913da3 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -7,6 +7,7 @@ * The following Boot Header format/structures and values are defined in the * following documents: * * ug1085 ZynqMP TRM doc v1.4 (Chapter 11, Table 11-4) + * * ug1137 ZynqMP Software Developer Guide v6.0 (Chapter 16) * * Expected Header Size = 0x9C0 * Forced as 'little' endian, 32-bit words @@ -63,6 +64,7 @@ #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_A53_64BIT (0x2 << 10) enum { ENCRYPTION_EFUSE = 0xa5c3c5a3, @@ -80,6 +82,78 @@ struct zynqmp_reginit { #define HEADER_INTERRUPT_VECTORS 8 #define HEADER_REGINITS 256 +struct image_header_table { + uint32_t version; /* 0x00 */ + uint32_t nr_parts; /* 0x04 */ + uint32_t partition_header_offset; /* 0x08, divided by 4 */ + uint32_t image_header_offset; /* 0x0c, divided by 4 */ + uint32_t auth_certificate_offset; /* 0x10 */ + uint32_t boot_device; /* 0x14 */ + uint32_t __reserved1[9]; /* 0x18 - 0x38 */ + uint32_t checksum; /* 0x3c */ +}; + +#define PART_ATTR_VEC_LOCATION 0x800000 +#define PART_ATTR_BS_BLOCK_SIZE_MASK 0x700000 +#define PART_ATTR_BS_BLOCK_SIZE_DEFAULT 0x000000 +#define PART_ATTR_BS_BLOCK_SIZE_8MB 0x400000 +#define PART_ATTR_BIG_ENDIAN 0x040000 +#define PART_ATTR_PART_OWNER_MASK 0x030000 +#define PART_ATTR_PART_OWNER_FSBL 0x000000 +#define PART_ATTR_PART_OWNER_UBOOT 0x010000 +#define PART_ATTR_RSA_SIG 0x008000 +#define PART_ATTR_CHECKSUM_MASK 0x007000 +#define PART_ATTR_CHECKSUM_NONE 0x000000 +#define PART_ATTR_CHECKSUM_MD5 0x001000 +#define PART_ATTR_CHECKSUM_SHA2 0x002000 +#define PART_ATTR_CHECKSUM_SHA3 0x003000 +#define PART_ATTR_DEST_CPU_SHIFT 8 +#define PART_ATTR_DEST_CPU_MASK 0x000f00 +#define PART_ATTR_DEST_CPU_NONE 0x000000 +#define PART_ATTR_DEST_CPU_A53_0 0x000100 +#define PART_ATTR_DEST_CPU_A53_1 0x000200 +#define PART_ATTR_DEST_CPU_A53_2 0x000300 +#define PART_ATTR_DEST_CPU_A53_3 0x000400 +#define PART_ATTR_DEST_CPU_R5_0 0x000500 +#define PART_ATTR_DEST_CPU_R5_1 0x000600 +#define PART_ATTR_DEST_CPU_R5_L 0x000700 +#define PART_ATTR_DEST_CPU_PMU 0x000800 +#define PART_ATTR_ENCRYPTED 0x000080 +#define PART_ATTR_DEST_DEVICE_SHIFT 4 +#define PART_ATTR_DEST_DEVICE_MASK 0x000070 +#define PART_ATTR_DEST_DEVICE_NONE 0x000000 +#define PART_ATTR_DEST_DEVICE_PS 0x000010 +#define PART_ATTR_DEST_DEVICE_PL 0x000020 +#define PART_ATTR_DEST_DEVICE_PMU 0x000030 +#define PART_ATTR_DEST_DEVICE_XIP 0x000040 +#define PART_ATTR_A53_EXEC_AARCH32 0x000008 +#define PART_ATTR_TARGET_EL_SHIFT 1 +#define PART_ATTR_TARGET_EL_MASK 0x000006 +#define PART_ATTR_TZ_SECURE 0x000001 + +static const char *dest_cpus[0x10] = { + "none", "a5x-0", "a5x-1", "a5x-2", "a5x-3", "r5-0", "r5-1", + "r5-lockstep", "pmu", "unknown", "unknown", "unknown", "unknown", + "unknown", "unknown", "unknown" +}; + +struct partition_header { + uint32_t len_enc; /* 0x00, divided by 4 */ + uint32_t len_unenc; /* 0x04, divided by 4 */ + uint32_t len; /* 0x08, divided by 4 */ + uint32_t next_partition_offset; /* 0x0c */ + uint64_t entry_point; /* 0x10 */ + uint64_t load_address; /* 0x18 */ + uint32_t offset; /* 0x20, divided by 4 */ + uint32_t attributes; /* 0x24 */ + uint32_t __reserved1; /* 0x28 */ + uint32_t checksum_offset; /* 0x2c, divided by 4 */ + uint32_t __reserved2; /* 0x30 */ + uint32_t auth_certificate_offset; /* 0x34 */ + uint32_t __reserved3; /* 0x38 */ + uint32_t checksum; /* 0x3c */ +}; + struct zynqmp_header { uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */ uint32_t width_detection; /* 0x20 */ @@ -93,7 +167,9 @@ struct zynqmp_header { uint32_t image_stored_size; /* 0x40 */ uint32_t image_attributes; /* 0x44 */ uint32_t checksum; /* 0x48 */ - uint32_t __reserved1[27]; /* 0x4c */ + uint32_t __reserved1[19]; /* 0x4c */ + uint32_t image_header_table_offset; /* 0x98 */ + uint32_t __reserved2[7]; /* 0x9c */ struct zynqmp_reginit register_init[HEADER_REGINITS]; /* 0xb8 */ uint32_t __reserved4[66]; /* 0x9c0 */ }; @@ -132,7 +208,7 @@ static void zynqmpimage_default_header(struct zynqmp_header *ptr) return; ptr->width_detection = HEADER_WIDTHDETECTION; - ptr->image_attributes = 0x800; + ptr->image_attributes = HEADER_CPU_SELECT_A53_64BIT; ptr->image_identifier = HEADER_IMAGEIDENTIFIER; ptr->encryption = cpu_to_le32(ENCRYPTION_NONE); @@ -173,6 +249,81 @@ static int zynqmpimage_verify_header(unsigned char *ptr, int image_size, return 0; } +static void print_partition(const void *ptr, const struct partition_header *ph) +{ + uint32_t attr = le32_to_cpu(ph->attributes); + unsigned long len = le32_to_cpu(ph->len) * 4; + const char *part_owner; + const char *dest_devs[0x8] = { + "none", "PS", "PL", "PMU", "unknown", "unknown", "unknown", + "unknown" + }; + + switch (attr & PART_ATTR_PART_OWNER_MASK) { + case PART_ATTR_PART_OWNER_FSBL: + part_owner = "FSBL"; + break; + case PART_ATTR_PART_OWNER_UBOOT: + part_owner = "U-Boot"; + break; + default: + part_owner = "Unknown"; + break; + } + + printf("%s payload on CPU %s (%s):\n", + part_owner, + dest_cpus[(attr & PART_ATTR_DEST_CPU_MASK) >> 8], + dest_devs[(attr & PART_ATTR_DEST_DEVICE_MASK) >> 4]); + + printf(" Offset : 0x%08x\n", le32_to_cpu(ph->offset) * 4); + printf(" Size : %lu (0x%lx) bytes\n", len, len); + printf(" Load : 0x%08llx", + (unsigned long long)le64_to_cpu(ph->load_address)); + if (ph->load_address != ph->entry_point) + printf(" (entry=0x%08llx)\n", + (unsigned long long)le64_to_cpu(ph->entry_point)); + else + printf("\n"); + printf(" Attributes : "); + + if (attr & PART_ATTR_VEC_LOCATION) + printf("vec "); + + if (attr & PART_ATTR_ENCRYPTED) + printf("encrypted "); + + switch (attr & PART_ATTR_CHECKSUM_MASK) { + case PART_ATTR_CHECKSUM_MD5: + printf("md5 "); + break; + case PART_ATTR_CHECKSUM_SHA2: + printf("sha2 "); + break; + case PART_ATTR_CHECKSUM_SHA3: + printf("sha3 "); + break; + } + + if (attr & PART_ATTR_BIG_ENDIAN) + printf("BigEndian "); + + if (attr & PART_ATTR_RSA_SIG) + printf("RSA "); + + if (attr & PART_ATTR_A53_EXEC_AARCH32) + printf("AArch32 "); + + if (attr & PART_ATTR_TARGET_EL_MASK) + printf("EL%d ", (attr & PART_ATTR_TARGET_EL_MASK) >> 1); + + if (attr & PART_ATTR_TZ_SECURE) + printf("secure "); + printf("\n"); + + printf(" Checksum : 0x%08x\n", le32_to_cpu(ph->checksum)); +} + static void zynqmpimage_print_header(const void *ptr) { struct zynqmp_header *zynqhdr = (struct zynqmp_header *)ptr; @@ -213,6 +364,25 @@ static void zynqmpimage_print_header(const void *ptr) le32_to_cpu(zynqhdr->register_init[i].data)); } + if (zynqhdr->image_header_table_offset) { + struct image_header_table *iht = (void*)ptr + + zynqhdr->image_header_table_offset; + struct partition_header *ph; + uint32_t ph_offset; + int i; + + ph_offset = le32_to_cpu(iht->partition_header_offset) * 4; + ph = (void*)ptr + ph_offset; + for (i = 0; i < le32_to_cpu(iht->nr_parts); i++) { + uint32_t next = le32_to_cpu(ph->next_partition_offset) * 4; + + /* Partition 0 is the base image itself */ + if (i) + print_partition(ptr, ph); + ph = (void*)ptr + next; + } + } + free(dynamic_header); } From patchwork Thu Apr 12 13:41:57 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Graf X-Patchwork-Id: 133278 Delivered-To: patch@linaro.org Received: by 10.46.84.29 with SMTP id i29csp1701844ljb; Thu, 12 Apr 2018 06:44:13 -0700 (PDT) X-Google-Smtp-Source: AIpwx48TeFNivUd0gr8YNC+27pSRczPsJ4Me4AB9lWxCJltg8+6D1l+HeD0bhriO8Wwfvp8XEJl+ X-Received: by 10.80.133.196 with SMTP id q4mr15793915edh.199.1523540653348; Thu, 12 Apr 2018 06:44:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523540653; cv=none; d=google.com; s=arc-20160816; b=S+ZXtmNpQwl0MXe8O7RMWI7vBsDHlnXw+ShWXl3ycdIMp3DP7Ns/z1WNXyF/LrbkMt KvHr/fQV1l98r47fnkMJ8T5aGoEksJBnknGZBiBVYm75wqCO0vHbulsO3Qb1qsSqwPoy 05VbW+mk3RmksS4+NQP8WfztqPA4B7Y812m6eTuoipaqw0i4wmEkqxmT+EEgjpmIXEiS Bvexpf+7KNtasZA9lUxg2aqCxSLxEMRMD4x+Pkuz2SqmxEaibS8lnTIHeybjHAWvrNJy tGWrOWaVnWdvrxXQ/lemUDpuhSYjui/AFbvTVuIYztdKN0Rl9NYTDNmSQaAimTD9nTdN u4tQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:arc-authentication-results; bh=yogmsEoTlKUBZyBBJ8blAhjGkvNi6iluFiHs9tHrzkM=; b=Y9iLtrqbuMC6VAValzxNuzSg96ND4VER2E6POsjzVUkoZORIM730c0OeEeQX9z1MJU XEi/9cazqDWrbP3d9aM0u0v5qf1cukuDxbHNFxh4d44KgKhWcmDIqNsLAyjcZZJNznCr 3JV243CWKEv2fHwqnS4wPzgVqejRzGPKGtXiLGoTmAMcwWMvI+mY5pNeZaGGjMQpmyp+ GSSQ2x3fctQoDQT8U8OzuXHfzmU1eMNPuAY9c00AoSEb7YvPic4zsTNYuMVNQrSBlbbo aO2v5MLm7LYoMuP9sIgTCxzbiNY3YBQvUQit67iF4JABMHImC/OTgvXL8Npppt1Yh6Hg /Ruw== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id e13si3811338eda.458.2018.04.12.06.44.13; Thu, 12 Apr 2018 06:44:13 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id D9AD1C21DD7; Thu, 12 Apr 2018 13:43:35 +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=none 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 5862FC21C2F; Thu, 12 Apr 2018 13:42:06 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id CD9B2C21C38; Thu, 12 Apr 2018 13:42:01 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by lists.denx.de (Postfix) with ESMTPS id 0167CC21C50 for ; Thu, 12 Apr 2018 13:42:01 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 30DC0AEC2; Thu, 12 Apr 2018 13:42:00 +0000 (UTC) From: Alexander Graf To: u-boot@lists.denx.de Date: Thu, 12 Apr 2018 15:41:57 +0200 Message-Id: <20180412134158.69300-3-agraf@suse.de> X-Mailer: git-send-email 2.12.3 In-Reply-To: <20180412134158.69300-1-agraf@suse.de> References: <20180412134158.69300-1-agraf@suse.de> Subject: [U-Boot] [PATCH v2 2/3] tools: zynqmpimage: Move defines to header 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" We will add support for ZynqMP bif input files later, so let's move all structure definitions into a header file that can be used by that one as well. Signed-off-by: Alexander Graf --- tools/zynqmpimage.c | 115 +-------------------------------------------- tools/zynqmpimage.h | 132 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 114 deletions(-) create mode 100644 tools/zynqmpimage.h diff --git a/tools/zynqmpimage.c b/tools/zynqmpimage.c index 8117913da3..8f4766f077 100644 --- a/tools/zynqmpimage.c +++ b/tools/zynqmpimage.c @@ -58,122 +58,9 @@ #include "imagetool.h" #include "mkimage.h" +#include "zynqmpimage.h" #include -#define HEADER_INTERRUPT_DEFAULT (cpu_to_le32(0xeafffffe)) -#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_A53_64BIT (0x2 << 10) - -enum { - ENCRYPTION_EFUSE = 0xa5c3c5a3, - ENCRYPTION_OEFUSE = 0xa5c3c5a7, - ENCRYPTION_BBRAM = 0x3a5c3c5a, - ENCRYPTION_OBBRAM = 0xa35c7ca5, - ENCRYPTION_NONE = 0x0, -}; - -struct zynqmp_reginit { - uint32_t address; - uint32_t data; -}; - -#define HEADER_INTERRUPT_VECTORS 8 -#define HEADER_REGINITS 256 - -struct image_header_table { - uint32_t version; /* 0x00 */ - uint32_t nr_parts; /* 0x04 */ - uint32_t partition_header_offset; /* 0x08, divided by 4 */ - uint32_t image_header_offset; /* 0x0c, divided by 4 */ - uint32_t auth_certificate_offset; /* 0x10 */ - uint32_t boot_device; /* 0x14 */ - uint32_t __reserved1[9]; /* 0x18 - 0x38 */ - uint32_t checksum; /* 0x3c */ -}; - -#define PART_ATTR_VEC_LOCATION 0x800000 -#define PART_ATTR_BS_BLOCK_SIZE_MASK 0x700000 -#define PART_ATTR_BS_BLOCK_SIZE_DEFAULT 0x000000 -#define PART_ATTR_BS_BLOCK_SIZE_8MB 0x400000 -#define PART_ATTR_BIG_ENDIAN 0x040000 -#define PART_ATTR_PART_OWNER_MASK 0x030000 -#define PART_ATTR_PART_OWNER_FSBL 0x000000 -#define PART_ATTR_PART_OWNER_UBOOT 0x010000 -#define PART_ATTR_RSA_SIG 0x008000 -#define PART_ATTR_CHECKSUM_MASK 0x007000 -#define PART_ATTR_CHECKSUM_NONE 0x000000 -#define PART_ATTR_CHECKSUM_MD5 0x001000 -#define PART_ATTR_CHECKSUM_SHA2 0x002000 -#define PART_ATTR_CHECKSUM_SHA3 0x003000 -#define PART_ATTR_DEST_CPU_SHIFT 8 -#define PART_ATTR_DEST_CPU_MASK 0x000f00 -#define PART_ATTR_DEST_CPU_NONE 0x000000 -#define PART_ATTR_DEST_CPU_A53_0 0x000100 -#define PART_ATTR_DEST_CPU_A53_1 0x000200 -#define PART_ATTR_DEST_CPU_A53_2 0x000300 -#define PART_ATTR_DEST_CPU_A53_3 0x000400 -#define PART_ATTR_DEST_CPU_R5_0 0x000500 -#define PART_ATTR_DEST_CPU_R5_1 0x000600 -#define PART_ATTR_DEST_CPU_R5_L 0x000700 -#define PART_ATTR_DEST_CPU_PMU 0x000800 -#define PART_ATTR_ENCRYPTED 0x000080 -#define PART_ATTR_DEST_DEVICE_SHIFT 4 -#define PART_ATTR_DEST_DEVICE_MASK 0x000070 -#define PART_ATTR_DEST_DEVICE_NONE 0x000000 -#define PART_ATTR_DEST_DEVICE_PS 0x000010 -#define PART_ATTR_DEST_DEVICE_PL 0x000020 -#define PART_ATTR_DEST_DEVICE_PMU 0x000030 -#define PART_ATTR_DEST_DEVICE_XIP 0x000040 -#define PART_ATTR_A53_EXEC_AARCH32 0x000008 -#define PART_ATTR_TARGET_EL_SHIFT 1 -#define PART_ATTR_TARGET_EL_MASK 0x000006 -#define PART_ATTR_TZ_SECURE 0x000001 - -static const char *dest_cpus[0x10] = { - "none", "a5x-0", "a5x-1", "a5x-2", "a5x-3", "r5-0", "r5-1", - "r5-lockstep", "pmu", "unknown", "unknown", "unknown", "unknown", - "unknown", "unknown", "unknown" -}; - -struct partition_header { - uint32_t len_enc; /* 0x00, divided by 4 */ - uint32_t len_unenc; /* 0x04, divided by 4 */ - uint32_t len; /* 0x08, divided by 4 */ - uint32_t next_partition_offset; /* 0x0c */ - uint64_t entry_point; /* 0x10 */ - uint64_t load_address; /* 0x18 */ - uint32_t offset; /* 0x20, divided by 4 */ - uint32_t attributes; /* 0x24 */ - uint32_t __reserved1; /* 0x28 */ - uint32_t checksum_offset; /* 0x2c, divided by 4 */ - uint32_t __reserved2; /* 0x30 */ - uint32_t auth_certificate_offset; /* 0x34 */ - uint32_t __reserved3; /* 0x38 */ - uint32_t checksum; /* 0x3c */ -}; - -struct zynqmp_header { - uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */ - uint32_t width_detection; /* 0x20 */ - uint32_t image_identifier; /* 0x24 */ - uint32_t encryption; /* 0x28 */ - uint32_t image_load; /* 0x2c */ - uint32_t image_offset; /* 0x30 */ - uint32_t pfw_image_length; /* 0x34 */ - uint32_t total_pfw_image_length; /* 0x38 */ - uint32_t image_size; /* 0x3c */ - uint32_t image_stored_size; /* 0x40 */ - uint32_t image_attributes; /* 0x44 */ - uint32_t checksum; /* 0x48 */ - uint32_t __reserved1[19]; /* 0x4c */ - uint32_t image_header_table_offset; /* 0x98 */ - uint32_t __reserved2[7]; /* 0x9c */ - struct zynqmp_reginit register_init[HEADER_REGINITS]; /* 0xb8 */ - uint32_t __reserved4[66]; /* 0x9c0 */ -}; - static struct zynqmp_header zynqmpimage_header; static void *dynamic_header; static FILE *fpmu; diff --git a/tools/zynqmpimage.h b/tools/zynqmpimage.h new file mode 100644 index 0000000000..f3b5c195ad --- /dev/null +++ b/tools/zynqmpimage.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2016 Michal Simek + * Copyright (C) 2015 Nathan Rossi + * + * SPDX-License-Identifier: GPL-2.0+ + * + * The following Boot Header format/structures and values are defined in the + * following documents: + * * ug1085 ZynqMP TRM doc v1.4 (Chapter 11, Table 11-4) + * * ug1137 ZynqMP Software Developer Guide v6.0 (Chapter 16) + */ + +#ifndef _ZYNQMPIMAGE_H_ +#define _ZYNQMPIMAGE_H_ + +#include + +#define HEADER_INTERRUPT_DEFAULT (cpu_to_le32(0xeafffffe)) +#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_A53_64BIT (0x2 << 10) + +enum { + ENCRYPTION_EFUSE = 0xa5c3c5a3, + ENCRYPTION_OEFUSE = 0xa5c3c5a7, + ENCRYPTION_BBRAM = 0x3a5c3c5a, + ENCRYPTION_OBBRAM = 0xa35c7ca5, + ENCRYPTION_NONE = 0x0, +}; + +struct zynqmp_reginit { + uint32_t address; + uint32_t data; +}; + +#define HEADER_INTERRUPT_VECTORS 8 +#define HEADER_REGINITS 256 + +struct image_header_table { + uint32_t version; /* 0x00 */ + uint32_t nr_parts; /* 0x04 */ + uint32_t partition_header_offset; /* 0x08, divided by 4 */ + uint32_t image_header_offset; /* 0x0c, divided by 4 */ + uint32_t auth_certificate_offset; /* 0x10 */ + uint32_t boot_device; /* 0x14 */ + uint32_t __reserved1[9]; /* 0x18 - 0x38 */ + uint32_t checksum; /* 0x3c */ +}; + +#define PART_ATTR_VEC_LOCATION 0x800000 +#define PART_ATTR_BS_BLOCK_SIZE_MASK 0x700000 +#define PART_ATTR_BS_BLOCK_SIZE_DEFAULT 0x000000 +#define PART_ATTR_BS_BLOCK_SIZE_8MB 0x400000 +#define PART_ATTR_BIG_ENDIAN 0x040000 +#define PART_ATTR_PART_OWNER_MASK 0x030000 +#define PART_ATTR_PART_OWNER_FSBL 0x000000 +#define PART_ATTR_PART_OWNER_UBOOT 0x010000 +#define PART_ATTR_RSA_SIG 0x008000 +#define PART_ATTR_CHECKSUM_MASK 0x007000 +#define PART_ATTR_CHECKSUM_NONE 0x000000 +#define PART_ATTR_CHECKSUM_MD5 0x001000 +#define PART_ATTR_CHECKSUM_SHA2 0x002000 +#define PART_ATTR_CHECKSUM_SHA3 0x003000 +#define PART_ATTR_DEST_CPU_SHIFT 8 +#define PART_ATTR_DEST_CPU_MASK 0x000f00 +#define PART_ATTR_DEST_CPU_NONE 0x000000 +#define PART_ATTR_DEST_CPU_A53_0 0x000100 +#define PART_ATTR_DEST_CPU_A53_1 0x000200 +#define PART_ATTR_DEST_CPU_A53_2 0x000300 +#define PART_ATTR_DEST_CPU_A53_3 0x000400 +#define PART_ATTR_DEST_CPU_R5_0 0x000500 +#define PART_ATTR_DEST_CPU_R5_1 0x000600 +#define PART_ATTR_DEST_CPU_R5_L 0x000700 +#define PART_ATTR_DEST_CPU_PMU 0x000800 +#define PART_ATTR_ENCRYPTED 0x000080 +#define PART_ATTR_DEST_DEVICE_SHIFT 4 +#define PART_ATTR_DEST_DEVICE_MASK 0x000070 +#define PART_ATTR_DEST_DEVICE_NONE 0x000000 +#define PART_ATTR_DEST_DEVICE_PS 0x000010 +#define PART_ATTR_DEST_DEVICE_PL 0x000020 +#define PART_ATTR_DEST_DEVICE_PMU 0x000030 +#define PART_ATTR_DEST_DEVICE_XIP 0x000040 +#define PART_ATTR_A53_EXEC_AARCH32 0x000008 +#define PART_ATTR_TARGET_EL_SHIFT 1 +#define PART_ATTR_TARGET_EL_MASK 0x000006 +#define PART_ATTR_TZ_SECURE 0x000001 + +static const char *dest_cpus[0x10] = { + "none", "a5x-0", "a5x-1", "a5x-2", "a5x-3", "r5-0", "r5-1", + "r5-lockstep", "pmu", "unknown", "unknown", "unknown", "unknown", + "unknown", "unknown", "unknown" +}; + +struct partition_header { + uint32_t len_enc; /* 0x00, divided by 4 */ + uint32_t len_unenc; /* 0x04, divided by 4 */ + uint32_t len; /* 0x08, divided by 4 */ + uint32_t next_partition_offset; /* 0x0c */ + uint64_t entry_point; /* 0x10 */ + uint64_t load_address; /* 0x18 */ + uint32_t offset; /* 0x20, divided by 4 */ + uint32_t attributes; /* 0x24 */ + uint32_t __reserved1; /* 0x28 */ + uint32_t checksum_offset; /* 0x2c, divided by 4 */ + uint32_t __reserved2; /* 0x30 */ + uint32_t auth_certificate_offset; /* 0x34 */ + uint32_t __reserved3; /* 0x38 */ + uint32_t checksum; /* 0x3c */ +}; + +struct zynqmp_header { + uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */ + uint32_t width_detection; /* 0x20 */ + uint32_t image_identifier; /* 0x24 */ + uint32_t encryption; /* 0x28 */ + uint32_t image_load; /* 0x2c */ + uint32_t image_offset; /* 0x30 */ + uint32_t pfw_image_length; /* 0x34 */ + uint32_t total_pfw_image_length; /* 0x38 */ + uint32_t image_size; /* 0x3c */ + uint32_t image_stored_size; /* 0x40 */ + uint32_t image_attributes; /* 0x44 */ + uint32_t checksum; /* 0x48 */ + uint32_t __reserved1[19]; /* 0x4c */ + uint32_t image_header_table_offset; /* 0x98 */ + uint32_t __reserved2[7]; /* 0x9c */ + struct zynqmp_reginit register_init[HEADER_REGINITS]; /* 0xb8 */ + uint32_t __reserved4[66]; /* 0x9c0 */ +}; + +#endif /* _ZYNQMPIMAGE_H_ */ From patchwork Thu Apr 12 13:41:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Graf X-Patchwork-Id: 133276 Delivered-To: patch@linaro.org Received: by 10.46.84.29 with SMTP id i29csp1700835ljb; Thu, 12 Apr 2018 06:43:01 -0700 (PDT) X-Google-Smtp-Source: AIpwx48Ox9EzTKgl9adV5Kxh49ivJ0MEtviNZiohdeBaAO2/yjLowZCkWlhINmc9buM+6iSPK6xH X-Received: by 10.80.247.129 with SMTP id h1mr14828273edn.293.1523540581254; Thu, 12 Apr 2018 06:43:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1523540581; cv=none; d=google.com; s=arc-20160816; b=lcaVuKZ+9Wzn2uWlV3vB4cBGYFqTrwG9xugAQustvp+6BELS/WEYRZbh1Ne8cxDzdz PSjpQg84w8QLpMIbLZv9P7ns1a6TiDmeNTTaLD7HTZT59CfoxX15ah1t5UKU7JDE25cH U9Ga/O2fdPNP2UNDLh3uWmY4zBR7oK6LHDY7vn88zyHg5UPsBQtl8T9kb1Qkbum2dNMt c5BbkkNXU+zJP5cx+mHtg9n+ONIklSG5Hx6CZ6RGC+/c6ZEA4UOVg58PaCS4pgPP+gC6 FbpSrV5CBzJBolvd9c16nmaD3Yp9T18832QX39dG2CSDjxzlx9WBiPwSq4EUAaJPU6AW Kwxw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:mime-version :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:references:in-reply-to:message-id:date :to:from:arc-authentication-results; bh=btpyise1qB+eztr5jOB3Ylz8JMr/y6du716lc5u7dPY=; b=GvnzlsqqLThAMJIMTo+LoVUUFc7ILvBsGL5s2yTncFs6y/YL5AKm9AynQ1kKEeDZra FDrV4VQQz2p9aRwzZF+SU5W+Du0TtZpRxRiIu/QS87pmFYyIg3qWoZcXYdS1S5bj/BPq hsFKc/43pmvHO/RerCvy2y1TbYuG3e+/PqS6kPUPNEsLKfwOey+UiyUmFhYX1deXsaDJ 3Sxn30krWHIikQe7VS+BfLW7RRulxMin8GL8Ro28tF7UD0IfBZj5BKPvu2AdN7sSdGoG FXkCR1UlC96ftJqOzi1OsMZ65xkJIlUOw29MX0v3TJ5ZHIe41C7MwI7OM4CCIyXc0yeC tDOQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Return-Path: Received: from lists.denx.de (dione.denx.de. [81.169.180.215]) by mx.google.com with ESMTP id e24si2936959edc.275.2018.04.12.06.43.00; Thu, 12 Apr 2018 06:43:01 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) client-ip=81.169.180.215; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of u-boot-bounces@lists.denx.de designates 81.169.180.215 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de Received: by lists.denx.de (Postfix, from userid 105) id CD9C4C21C6A; Thu, 12 Apr 2018 13:42:52 +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=none 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 0653FC21DAF; Thu, 12 Apr 2018 13:42:05 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id B1D4CC21C2F; Thu, 12 Apr 2018 13:42:01 +0000 (UTC) Received: from mx2.suse.de (mx2.suse.de [195.135.220.15]) by lists.denx.de (Postfix) with ESMTPS id 00BF4C21C38 for ; Thu, 12 Apr 2018 13:42:01 +0000 (UTC) X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id 2F041AE0C; Thu, 12 Apr 2018 13:42:00 +0000 (UTC) From: Alexander Graf To: u-boot@lists.denx.de Date: Thu, 12 Apr 2018 15:41:58 +0200 Message-Id: <20180412134158.69300-4-agraf@suse.de> X-Mailer: git-send-email 2.12.3 In-Reply-To: <20180412134158.69300-1-agraf@suse.de> References: <20180412134158.69300-1-agraf@suse.de> Subject: [U-Boot] [PATCH v2 3/3] tools: zynqmpimage: Add bif support 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" 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 --- common/image.c | 1 + include/image.h | 1 + tools/Makefile | 1 + tools/imagetool.h | 1 + tools/mkimage.c | 3 + tools/zynqmpbif.c | 839 ++++++++++++++++++++++++++++++++++++++++++++++++++++ tools/zynqmpimage.c | 4 +- tools/zynqmpimage.h | 3 + 8 files changed, 851 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..d78a9458f4 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); +void 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..72183f5f2b 100644 --- a/tools/mkimage.c +++ b/tools/mkimage.c @@ -514,6 +514,9 @@ 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 */ + zynqmpbif_copy_image(ifd, ¶ms); } else { copy_file(ifd, params.datafile, pad_len); } diff --git a/tools/zynqmpbif.c b/tools/zynqmpbif.c new file mode 100644 index 0000000000..47218873eb --- /dev/null +++ b/tools/zynqmpbif.c @@ -0,0 +1,839 @@ +/* + * 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; +}; + +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, + + /* 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) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(dest_cpus); i++) { + if (!strncmp(line, dest_cpus[i], strlen(dest_cpus[i]))) { + bf->dest_cpu = i; + return line + strlen(dest_cpus[i]); + } + } + + 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 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 }, +}; + +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; + + bufp = buf = malloc(sbuf.st_size); + if (!buf) + return NULL; + + 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 = ROUND(bif_output.data_len + len, 64); + uintptr_t header_off; + uintptr_t last_part_off; + uintptr_t imgheader_off; + uintptr_t old_data = (uintptr_t)bif_output.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; + + bif_output.data = realloc(bif_output.data, new_size); + memcpy(bif_output.data + bif_output.data_len, data, len); + if (offset) + *offset = bif_output.data_len; + bif_output.data_len = new_size; + + /* Readjust internal pointers */ + if (bif_output.header) + bif_output.header = (void*)(bif_output.data + header_off); + if (bif_output.last_part) + bif_output.last_part = (void*)(bif_output.data + last_part_off); + if (bif_output.imgheader) + bif_output.imgheader = (void*)(bif_output.data + imgheader_off); + + return 0; +} + +static int bif_init(void) +{ + struct zynqmp_header header; + 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) +{ + size_t offset; + + if (bif_output.header->image_offset) { + printf("PMUFW expected before bootloader in your .bif file!\n"); + return -1; + } + + bif_add_blob(data, len, &offset); + 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(offset); + + return 0; +} + +static int bif_add_part(struct bif_entry *bf, const char *data, size_t len) +{ + size_t parthdr_offset, part_offset; + 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); + + bif_add_blob(data, len, &part_offset); + parthdr.offset = cpu_to_le32(part_offset / 4); + + if (bf->flags & (1ULL << BIF_FLAG_BOOTLOADER)) { + if (bif_output.last_part) { + printf("ERROR: Bootloader needs to come as first non-PMU partition"); + return -1; + } + + parthdr.offset = cpu_to_le32(bif_output.header->image_offset); + parthdr.len = cpu_to_le32((part_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 << PART_ATTR_DEST_CPU_SHIFT; + if (bf->flags & (1ULL << BIF_FLAG_TZ)) + parthdr.attributes |= PART_ATTR_TZ_SECURE; + + 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; + 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(part_offset); + bif_output.header->image_size = cpu_to_le32(len); + bif_output.header->image_stored_size = cpu_to_le32(len); + } + + 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); + printf("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); + printf("Device: %s\n", bit); + bit += len; + + /* Date */ + if (*bit != 'c') + return -1; + bit++; + len = be16_to_cpu(*(uint16_t*)bit); + bit += sizeof(uint16_t); + printf("Date: %s\n", bit); + bit += len; + + /* Time */ + if (*bit != 'd') + return -1; + bit++; + len = be16_to_cpu(*(uint16_t*)bit); + bit += sizeof(uint16_t); + printf("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; + + printf("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++) { + if (!shdr->sh_size || !shdr->sh_addr || + !(shdr->sh_flags & SHF_ALLOC) || + (shdr->sh_type == SHT_NOBITS)) { + shdr++; + 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); + + shdr++; + } + + *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++) { + 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)) { + shdr++; + continue; + } + + if (shdr->sh_type != SHT_NOBITS) { + + memcpy(dst, src, le64_to_cpu(shdr->sh_size)); + } + shdr++; + } + + 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++) { + if (!shdr->sh_size || !shdr->sh_addr || + !(shdr->sh_flags & SHF_ALLOC) || + (shdr->sh_type == SHT_NOBITS)) { + shdr++; + 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); + + shdr++; + } + + *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++) { + 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)) { + shdr++; + continue; + } + + if (shdr->sh_type != SHT_NOBITS) { + + memcpy(dst, src, le32_to_cpu(shdr->sh_size)); + } + shdr++; + } + + 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); + 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 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; +} + +void 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; + + bif_init(); + + /* Read .bif input file */ + bifp = 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'); + + *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; + + /* 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); + } + + for (i = 0; i < nr_entries; i++) { + struct bif_entry *entry = &entries[i]; + const struct bif_file_type *type; + int r; + + 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; + +err: + fprintf(stderr, "Error: Failed to create image.\n"); +} + +/* 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 8f4766f077..145391de3e 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; @@ -211,7 +211,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..b421e4f94c 100644 --- a/tools/zynqmpimage.h +++ b/tools/zynqmpimage.h @@ -129,4 +129,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_ */