Commit 66eef1e780caf0bb3ecadf78582a29031c6279ce

Authored by Nathan Rossi
Committed by Michal Simek
1 parent bf146325a3

tools: zynqimage: Add Xilinx Zynq boot header generation to mkimage

As with other platforms vendors love to create their own boot header
formats. Xilinx is no different and for the Zynq platform/SoC there
exists the "boot.bin" which is read by the platforms bootrom. This
format is described to a useful extent within the Xilinx Zynq TRM.

This implementation adds support for the 'zynqimage' to mkimage. The
implementation only considers the most common boot header which is
un-encrypted and packed directly after the boot header itself (no
XIP, etc.). However this implementation does take into consideration the
other fields of the header for image dumping use cases (vector table and
register initialization).

Signed-off-by: Nathan Rossi <nathan@nathanrossi.com>
Cc: Michal Simek <michal.simek@xilinx.com>
Cc: Tom Rini <trini@konsulko.com>
Reviewed-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>

Showing 4 changed files with 261 additions and 1 deletions Side-by-side Diff

... ... @@ -158,6 +158,7 @@
158 158 { IH_TYPE_RKIMAGE, "rkimage", "Rockchip Boot Image" },
159 159 { IH_TYPE_RKSD, "rksd", "Rockchip SD Boot Image" },
160 160 { IH_TYPE_RKSPI, "rkspi", "Rockchip SPI Boot Image" },
  161 + { IH_TYPE_ZYNQIMAGE, "zynqimage", "Xilinx Zynq Boot Image" },
161 162 { -1, "", "", },
162 163 };
163 164  
... ... @@ -248,8 +248,9 @@
248 248 #define IH_TYPE_RKIMAGE 23 /* Rockchip Boot Image */
249 249 #define IH_TYPE_RKSD 24 /* Rockchip SD card */
250 250 #define IH_TYPE_RKSPI 25 /* Rockchip SPI image */
  251 +#define IH_TYPE_ZYNQIMAGE 26 /* Xilinx Zynq Boot Image */
251 252  
252   -#define IH_TYPE_COUNT 26 /* Number of image types */
  253 +#define IH_TYPE_COUNT 27 /* Number of image types */
253 254  
254 255 /*
255 256 * Compression Types
... ... @@ -98,6 +98,7 @@
98 98 lib/sha256.o \
99 99 common/hash.o \
100 100 ublimage.o \
  101 + zynqimage.o \
101 102 $(LIBFDT_OBJS) \
102 103 $(RSA_OBJS-y)
103 104  
  1 +/*
  2 + * Copyright (C) 2015 Nathan Rossi <nathan@nathanrossi.com>
  3 + *
  4 + * SPDX-License-Identifier: GPL-2.0+
  5 + *
  6 + * The following Boot Header format/structures and values are defined in the
  7 + * following documents:
  8 + * * Xilinx Zynq-7000 Technical Reference Manual (Section 6.3)
  9 + * * Xilinx Zynq-7000 Software Developers Guide (Appendix A.7 and A.8)
  10 + *
  11 + * Expected Header Size = 0x8C0
  12 + * Forced as 'little' endian, 32-bit words
  13 + *
  14 + * 0x 0 - Interrupt Table (8 words)
  15 + * ... (Default value = 0xeafffffe)
  16 + * 0x 1f
  17 + * 0x 20 - Width Detection
  18 + * * DEFAULT_WIDTHDETECTION 0xaa995566
  19 + * 0x 24 - Image Identifier
  20 + * * DEFAULT_IMAGEIDENTIFIER 0x584c4e58
  21 + * 0x 28 - Encryption
  22 + * * 0x00000000 - None
  23 + * * 0xa5c3c5a3 - eFuse
  24 + * * 0x3a5c3c5a - bbRam
  25 + * 0x 2C - User Field
  26 + * 0x 30 - Image Offset
  27 + * 0x 34 - Image Size
  28 + * 0x 38 - Reserved (0x00000000) (according to spec)
  29 + * * FSBL defines this field for Image Destination Address.
  30 + * 0x 3C - Image Load
  31 + * 0x 40 - Image Stored Size
  32 + * 0x 44 - Reserved (0x00000000) (according to spec)
  33 + * * FSBL defines this field for QSPI configuration Data.
  34 + * 0x 48 - Checksum
  35 + * 0x 4c - Unused (21 words)
  36 + * ...
  37 + * 0x 9c
  38 + * 0x a0 - Register Initialization, 256 Address and Data word pairs
  39 + * * List is terminated with an address of 0xffffffff or
  40 + * ... * at the max number of entries
  41 + * 0x89c
  42 + * 0x8a0 - Unused (8 words)
  43 + * ...
  44 + * 0x8bf
  45 + * 0x8c0 - Data/Image starts here or above
  46 + */
  47 +
  48 +#include "imagetool.h"
  49 +#include "mkimage.h"
  50 +#include <image.h>
  51 +
  52 +#define HEADER_INTERRUPT_DEFAULT (cpu_to_le32(0xeafffffe))
  53 +#define HEADER_REGINIT_NULL (cpu_to_le32(0xffffffff))
  54 +#define HEADER_WIDTHDETECTION (cpu_to_le32(0xaa995566))
  55 +#define HEADER_IMAGEIDENTIFIER (cpu_to_le32(0x584c4e58))
  56 +
  57 +enum {
  58 + ENCRYPTION_EFUSE = 0xa5c3c5a3,
  59 + ENCRYPTION_BBRAM = 0x3a5c3c5a,
  60 + ENCRYPTION_NONE = 0x0,
  61 +};
  62 +
  63 +struct zynq_reginit {
  64 + uint32_t address;
  65 + uint32_t data;
  66 +};
  67 +
  68 +#define HEADER_INTERRUPT_VECTORS 8
  69 +#define HEADER_REGINITS 256
  70 +
  71 +struct zynq_header {
  72 + uint32_t interrupt_vectors[HEADER_INTERRUPT_VECTORS]; /* 0x0 */
  73 + uint32_t width_detection; /* 0x20 */
  74 + uint32_t image_identifier; /* 0x24 */
  75 + uint32_t encryption; /* 0x28 */
  76 + uint32_t user_field; /* 0x2c */
  77 + uint32_t image_offset; /* 0x30 */
  78 + uint32_t image_size; /* 0x34 */
  79 + uint32_t __reserved1; /* 0x38 */
  80 + uint32_t image_load; /* 0x3c */
  81 + uint32_t image_stored_size; /* 0x40 */
  82 + uint32_t __reserved2; /* 0x44 */
  83 + uint32_t checksum; /* 0x48 */
  84 + uint32_t __reserved3[21]; /* 0x4c */
  85 + struct zynq_reginit register_init[HEADER_REGINITS]; /* 0xa0 */
  86 + uint32_t __reserved4[8]; /* 0x8a0 */
  87 +};
  88 +
  89 +static struct zynq_header zynqimage_header;
  90 +
  91 +static uint32_t zynqimage_checksum(struct zynq_header *ptr)
  92 +{
  93 + uint32_t checksum = 0;
  94 +
  95 + if (ptr == NULL)
  96 + return 0;
  97 +
  98 + checksum += le32_to_cpu(ptr->width_detection);
  99 + checksum += le32_to_cpu(ptr->image_identifier);
  100 + checksum += le32_to_cpu(ptr->encryption);
  101 + checksum += le32_to_cpu(ptr->user_field);
  102 + checksum += le32_to_cpu(ptr->image_offset);
  103 + checksum += le32_to_cpu(ptr->image_size);
  104 + checksum += le32_to_cpu(ptr->__reserved1);
  105 + checksum += le32_to_cpu(ptr->image_load);
  106 + checksum += le32_to_cpu(ptr->image_stored_size);
  107 + checksum += le32_to_cpu(ptr->__reserved2);
  108 + checksum = ~checksum;
  109 +
  110 + return cpu_to_le32(checksum);
  111 +}
  112 +
  113 +static void zynqimage_default_header(struct zynq_header *ptr)
  114 +{
  115 + int i;
  116 +
  117 + if (ptr == NULL)
  118 + return;
  119 +
  120 + ptr->width_detection = HEADER_WIDTHDETECTION;
  121 + ptr->image_identifier = HEADER_IMAGEIDENTIFIER;
  122 + ptr->encryption = cpu_to_le32(ENCRYPTION_NONE);
  123 +
  124 + /* Setup not-supported/constant/reserved fields */
  125 + for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++)
  126 + ptr->interrupt_vectors[i] = HEADER_INTERRUPT_DEFAULT;
  127 +
  128 + for (i = 0; i < HEADER_REGINITS; i++) {
  129 + ptr->register_init[i].address = HEADER_REGINIT_NULL;
  130 + ptr->register_init[i].data = HEADER_REGINIT_NULL;
  131 + }
  132 +
  133 + /*
  134 + * Certain reserved fields are required to be set to 0, ensure they are
  135 + * set as such.
  136 + */
  137 + ptr->__reserved1 = 0x0;
  138 + ptr->__reserved2 = 0x0;
  139 +}
  140 +
  141 +/* mkimage glue functions */
  142 +static int zynqimage_verify_header(unsigned char *ptr, int image_size,
  143 + struct image_tool_params *params)
  144 +{
  145 + struct zynq_header *zynqhdr = (struct zynq_header *)ptr;
  146 +
  147 + if (image_size < sizeof(struct zynq_header))
  148 + return -1;
  149 +
  150 + if (zynqhdr->width_detection != HEADER_WIDTHDETECTION)
  151 + return -1;
  152 + if (zynqhdr->image_identifier != HEADER_IMAGEIDENTIFIER)
  153 + return -1;
  154 +
  155 + if (zynqimage_checksum(zynqhdr) != zynqhdr->checksum)
  156 + return -1;
  157 +
  158 + return 0;
  159 +}
  160 +
  161 +static void zynqimage_print_header(const void *ptr)
  162 +{
  163 + struct zynq_header *zynqhdr = (struct zynq_header *)ptr;
  164 + int i;
  165 +
  166 + printf("Image Type : Xilinx Zynq Boot Image support\n");
  167 + printf("Image Offset : 0x%08x\n", le32_to_cpu(zynqhdr->image_offset));
  168 + printf("Image Size : %lu bytes (%lu bytes packed)\n",
  169 + (unsigned long)le32_to_cpu(zynqhdr->image_size),
  170 + (unsigned long)le32_to_cpu(zynqhdr->image_stored_size));
  171 + printf("Image Load : 0x%08x\n", le32_to_cpu(zynqhdr->image_load));
  172 + printf("User Field : 0x%08x\n", le32_to_cpu(zynqhdr->user_field));
  173 + printf("Checksum : 0x%08x\n", le32_to_cpu(zynqhdr->checksum));
  174 +
  175 + for (i = 0; i < HEADER_INTERRUPT_VECTORS; i++) {
  176 + if (zynqhdr->interrupt_vectors[i] == HEADER_INTERRUPT_DEFAULT)
  177 + continue;
  178 +
  179 + printf("Modified Interrupt Vector Address [%d]: 0x%08x\n", i,
  180 + le32_to_cpu(zynqhdr->interrupt_vectors[i]));
  181 + }
  182 +
  183 + for (i = 0; i < HEADER_REGINITS; i++) {
  184 + if (zynqhdr->register_init[i].address == HEADER_REGINIT_NULL)
  185 + break;
  186 +
  187 + if (i == 0)
  188 + printf("Custom Register Initialization:\n");
  189 +
  190 + printf(" @ 0x%08x -> 0x%08x\n",
  191 + le32_to_cpu(zynqhdr->register_init[i].address),
  192 + le32_to_cpu(zynqhdr->register_init[i].data));
  193 + }
  194 +}
  195 +
  196 +static int zynqimage_check_params(struct image_tool_params *params)
  197 +{
  198 + if (!params)
  199 + return 0;
  200 +
  201 + if (params->addr != 0x0) {
  202 + fprintf(stderr, "Error: Load Address cannot be specified.\n");
  203 + return -1;
  204 + }
  205 +
  206 + /*
  207 + * If the entry point is specified ensure it is 64 byte aligned.
  208 + */
  209 + if (params->eflag && (params->ep % 64 != 0)) {
  210 + fprintf(stderr,
  211 + "Error: Entry Point must be aligned to a 64-byte boundary.\n");
  212 + return -1;
  213 + }
  214 +
  215 + return !((params->lflag || params->dflag) ||
  216 + (params->dflag && params->eflag));
  217 +}
  218 +
  219 +static int zynqimage_check_image_types(uint8_t type)
  220 +{
  221 + if (type == IH_TYPE_ZYNQIMAGE)
  222 + return EXIT_SUCCESS;
  223 + return EXIT_FAILURE;
  224 +}
  225 +
  226 +static void zynqimage_set_header(void *ptr, struct stat *sbuf, int ifd,
  227 + struct image_tool_params *params)
  228 +{
  229 + struct zynq_header *zynqhdr = (struct zynq_header *)ptr;
  230 + zynqimage_default_header(zynqhdr);
  231 +
  232 + /* place image directly after header */
  233 + zynqhdr->image_offset =
  234 + cpu_to_le32((uint32_t)sizeof(struct zynq_header));
  235 + zynqhdr->image_size = cpu_to_le32((uint32_t)sbuf->st_size);
  236 + zynqhdr->image_stored_size = zynqhdr->image_size;
  237 + zynqhdr->image_load = 0x0;
  238 + if (params->eflag)
  239 + zynqhdr->image_load = cpu_to_le32((uint32_t)params->ep);
  240 +
  241 + zynqhdr->checksum = zynqimage_checksum(zynqhdr);
  242 +}
  243 +
  244 +U_BOOT_IMAGE_TYPE(
  245 + zynqimage,
  246 + "Xilinx Zynq Boot Image support",
  247 + sizeof(struct zynq_header),
  248 + (void *)&zynqimage_header,
  249 + zynqimage_check_params,
  250 + zynqimage_verify_header,
  251 + zynqimage_print_header,
  252 + zynqimage_set_header,
  253 + NULL,
  254 + zynqimage_check_image_types,
  255 + NULL,
  256 + NULL
  257 +);