blob: 4fd93899f5c8ea008fca3ebcf1c57b4b09b239c4 [file] [log] [blame]
Prafulla Wadaskar07329412009-09-07 15:05:02 +05301/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +02002 * Image manipulator for Marvell SoCs
3 * supports Kirkwood, Dove, Armada 370, and Armada XP
4 *
5 * (C) Copyright 2013 Thomas Petazzoni
6 * <thomas.petazzoni@free-electrons.com>
Prafulla Wadaskar07329412009-09-07 15:05:02 +05307 *
Wolfgang Denkd79de1d2013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
Stefan Roese3b8b19d2014-10-22 12:13:23 +02009 *
10 * Not implemented: support for the register headers and secure
11 * headers in v1 images
Prafulla Wadaskar07329412009-09-07 15:05:02 +053012 */
13
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -070014#include "imagetool.h"
Andreas Bießmann7abec5b2014-10-24 23:39:11 +020015#include <limits.h>
Prafulla Wadaskar07329412009-09-07 15:05:02 +053016#include <image.h>
Stefan Roese3b8b19d2014-10-22 12:13:23 +020017#include <stdint.h>
Prafulla Wadaskar07329412009-09-07 15:05:02 +053018#include "kwbimage.h"
19
Stefan Roese3b8b19d2014-10-22 12:13:23 +020020static struct image_cfg_element *image_cfg;
21static int cfgn;
22
23struct boot_mode {
24 unsigned int id;
25 const char *name;
26};
27
28struct boot_mode boot_modes[] = {
29 { 0x4D, "i2c" },
30 { 0x5A, "spi" },
31 { 0x8B, "nand" },
32 { 0x78, "sata" },
33 { 0x9C, "pex" },
34 { 0x69, "uart" },
Stefan Roese539fe4a2015-07-20 11:20:37 +020035 { 0xAE, "sdio" },
Stefan Roese3b8b19d2014-10-22 12:13:23 +020036 {},
Prafulla Wadaskar07329412009-09-07 15:05:02 +053037};
38
Stefan Roese3b8b19d2014-10-22 12:13:23 +020039struct nand_ecc_mode {
40 unsigned int id;
41 const char *name;
42};
43
44struct nand_ecc_mode nand_ecc_modes[] = {
45 { 0x00, "default" },
46 { 0x01, "hamming" },
47 { 0x02, "rs" },
48 { 0x03, "disabled" },
49 {},
50};
51
52/* Used to identify an undefined execution or destination address */
53#define ADDR_INVALID ((uint32_t)-1)
54
55#define BINARY_MAX_ARGS 8
56
57/* In-memory representation of a line of the configuration file */
58struct image_cfg_element {
59 enum {
60 IMAGE_CFG_VERSION = 0x1,
61 IMAGE_CFG_BOOT_FROM,
62 IMAGE_CFG_DEST_ADDR,
63 IMAGE_CFG_EXEC_ADDR,
64 IMAGE_CFG_NAND_BLKSZ,
65 IMAGE_CFG_NAND_BADBLK_LOCATION,
66 IMAGE_CFG_NAND_ECC_MODE,
67 IMAGE_CFG_NAND_PAGESZ,
68 IMAGE_CFG_BINARY,
69 IMAGE_CFG_PAYLOAD,
70 IMAGE_CFG_DATA,
Chris Packham883bf452016-11-09 22:07:45 +130071 IMAGE_CFG_BAUDRATE,
Chris Packham1e0728a2016-11-09 22:21:45 +130072 IMAGE_CFG_DEBUG,
Stefan Roese3b8b19d2014-10-22 12:13:23 +020073 } type;
74 union {
75 unsigned int version;
76 unsigned int bootfrom;
77 struct {
78 const char *file;
79 unsigned int args[BINARY_MAX_ARGS];
80 unsigned int nargs;
81 } binary;
82 const char *payload;
83 unsigned int dstaddr;
84 unsigned int execaddr;
85 unsigned int nandblksz;
86 unsigned int nandbadblklocation;
87 unsigned int nandeccmode;
88 unsigned int nandpagesz;
89 struct ext_hdr_v0_reg regdata;
Chris Packham883bf452016-11-09 22:07:45 +130090 unsigned int baudrate;
Chris Packham1e0728a2016-11-09 22:21:45 +130091 unsigned int debug;
Stefan Roese3b8b19d2014-10-22 12:13:23 +020092 };
93};
94
95#define IMAGE_CFG_ELEMENT_MAX 256
Prafulla Wadaskar07329412009-09-07 15:05:02 +053096
97/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020098 * Utility functions to manipulate boot mode and ecc modes (convert
99 * them back and forth between description strings and the
100 * corresponding numerical identifiers).
101 */
102
103static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530104{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200105 int i;
Mario Sixd6009d72017-01-11 16:00:54 +0100106
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200107 for (i = 0; boot_modes[i].name; i++)
108 if (boot_modes[i].id == id)
109 return boot_modes[i].name;
110 return NULL;
111}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530112
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200113int image_boot_mode_id(const char *boot_mode_name)
114{
115 int i;
Mario Sixd6009d72017-01-11 16:00:54 +0100116
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200117 for (i = 0; boot_modes[i].name; i++)
118 if (!strcmp(boot_modes[i].name, boot_mode_name))
119 return boot_modes[i].id;
120
121 return -1;
122}
123
124int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
125{
126 int i;
Mario Sixd6009d72017-01-11 16:00:54 +0100127
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200128 for (i = 0; nand_ecc_modes[i].name; i++)
129 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
130 return nand_ecc_modes[i].id;
131 return -1;
132}
133
134static struct image_cfg_element *
135image_find_option(unsigned int optiontype)
136{
137 int i;
138
139 for (i = 0; i < cfgn; i++) {
140 if (image_cfg[i].type == optiontype)
141 return &image_cfg[i];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530142 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200143
144 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530145}
146
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200147static unsigned int
148image_count_options(unsigned int optiontype)
149{
150 int i;
151 unsigned int count = 0;
152
153 for (i = 0; i < cfgn; i++)
154 if (image_cfg[i].type == optiontype)
155 count++;
156
157 return count;
158}
159
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530160/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200161 * Compute a 8-bit checksum of a memory area. This algorithm follows
162 * the requirements of the Marvell SoC BootROM specifications.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530163 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200164static uint8_t image_checksum8(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530165{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200166 uint8_t csum = 0;
167 uint8_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530168
169 /* check len and return zero checksum if invalid */
170 if (!len)
171 return 0;
172
173 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200174 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530175 p++;
176 } while (--len);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200177
178 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530179}
180
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200181static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530182{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200183 uint32_t csum = 0;
184 uint32_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530185
186 /* check len and return zero checksum if invalid */
187 if (!len)
188 return 0;
189
190 if (len % sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200191 fprintf(stderr, "Length %d is not in multiple of %zu\n",
192 len, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530193 return 0;
194 }
195
196 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200197 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530198 p++;
199 len -= sizeof(uint32_t);
200 } while (len > 0);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200201
202 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530203}
204
Chris Packham883bf452016-11-09 22:07:45 +1300205static uint8_t baudrate_to_option(unsigned int baudrate)
206{
207 switch (baudrate) {
208 case 2400:
209 return MAIN_HDR_V1_OPT_BAUD_2400;
210 case 4800:
211 return MAIN_HDR_V1_OPT_BAUD_4800;
212 case 9600:
213 return MAIN_HDR_V1_OPT_BAUD_9600;
214 case 19200:
215 return MAIN_HDR_V1_OPT_BAUD_19200;
216 case 38400:
217 return MAIN_HDR_V1_OPT_BAUD_38400;
218 case 57600:
219 return MAIN_HDR_V1_OPT_BAUD_57600;
220 case 115200:
221 return MAIN_HDR_V1_OPT_BAUD_115200;
222 default:
223 return MAIN_HDR_V1_OPT_BAUD_DEFAULT;
224 }
225}
226
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200227static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
228 int payloadsz)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530229{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200230 struct image_cfg_element *e;
231 size_t headersz;
232 struct main_hdr_v0 *main_hdr;
Mario Six7497cd62017-01-11 16:00:55 +0100233 uint8_t *image;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200234 int has_ext = 0;
235
236 /*
237 * Calculate the size of the header and the size of the
238 * payload
239 */
240 headersz = sizeof(struct main_hdr_v0);
241
242 if (image_count_options(IMAGE_CFG_DATA) > 0) {
243 has_ext = 1;
244 headersz += sizeof(struct ext_hdr_v0);
245 }
246
247 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
248 fprintf(stderr, "More than one payload, not possible\n");
249 return NULL;
250 }
251
252 image = malloc(headersz);
253 if (!image) {
254 fprintf(stderr, "Cannot allocate memory for image\n");
255 return NULL;
256 }
257
258 memset(image, 0, headersz);
259
Mario Six7497cd62017-01-11 16:00:55 +0100260 main_hdr = (struct main_hdr_v0 *)image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530261
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200262 /* Fill in the main header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100263 main_hdr->blocksize =
264 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
265 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200266 main_hdr->ext = has_ext;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100267 main_hdr->destaddr = cpu_to_le32(params->addr);
268 main_hdr->execaddr = cpu_to_le32(params->ep);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530269
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200270 e = image_find_option(IMAGE_CFG_BOOT_FROM);
271 if (e)
272 main_hdr->blockid = e->bootfrom;
273 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
274 if (e)
275 main_hdr->nandeccmode = e->nandeccmode;
276 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
277 if (e)
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100278 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200279 main_hdr->checksum = image_checksum8(image,
280 sizeof(struct main_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530281
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200282 /* Generate the ext header */
283 if (has_ext) {
Mario Six6f273632017-01-11 16:00:56 +0100284 struct ext_hdr_v0 *ext_hdr;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200285 int cfgi, datai;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530286
Mario Six7497cd62017-01-11 16:00:55 +0100287 ext_hdr = (struct ext_hdr_v0 *)
288 (image + sizeof(struct main_hdr_v0));
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100289 ext_hdr->offset = cpu_to_le32(0x40);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530290
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200291 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
292 e = &image_cfg[cfgi];
293 if (e->type != IMAGE_CFG_DATA)
294 continue;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530295
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100296 ext_hdr->rcfg[datai].raddr =
297 cpu_to_le32(e->regdata.raddr);
298 ext_hdr->rcfg[datai].rdata =
299 cpu_to_le32(e->regdata.rdata);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200300 datai++;
301 }
302
303 ext_hdr->checksum = image_checksum8(ext_hdr,
304 sizeof(struct ext_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530305 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530306
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200307 *imagesz = headersz;
308 return image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530309}
310
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200311static size_t image_headersz_v1(struct image_tool_params *params,
312 int *hasext)
313{
314 struct image_cfg_element *binarye;
315 size_t headersz;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530316
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200317 /*
318 * Calculate the size of the header and the size of the
319 * payload
320 */
321 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530322
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200323 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
324 fprintf(stderr, "More than one binary blob, not supported\n");
325 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530326 }
327
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200328 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
329 fprintf(stderr, "More than one payload, not possible\n");
330 return 0;
331 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530332
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200333 binarye = image_find_option(IMAGE_CFG_BINARY);
334 if (binarye) {
Mario Six6f273632017-01-11 16:00:56 +0100335 int ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200336 struct stat s;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530337
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200338 ret = stat(binarye->binary.file, &s);
339 if (ret < 0) {
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200340 char cwd[PATH_MAX];
341 char *dir = cwd;
342
343 memset(cwd, 0, sizeof(cwd));
344 if (!getcwd(cwd, sizeof(cwd))) {
345 dir = "current working directory";
346 perror("getcwd() failed");
347 }
348
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200349 fprintf(stderr,
350 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
351 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
352 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200353 binarye->binary.file, dir);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200354 return 0;
355 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530356
Reinhard Pfau5286c0d2015-11-29 15:52:14 +0100357 headersz += sizeof(struct opt_hdr_v1) +
358 s.st_size +
359 (binarye->binary.nargs + 2) * sizeof(uint32_t);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200360 if (hasext)
361 *hasext = 1;
362 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530363
Stefan Roese69e9dde2015-07-20 11:20:38 +0200364#if defined(CONFIG_SYS_U_BOOT_OFFS)
365 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
Mario Sixd6009d72017-01-11 16:00:54 +0100366 fprintf(stderr,
367 "Error: Image header (incl. SPL image) too big!\n");
Stefan Roese69e9dde2015-07-20 11:20:38 +0200368 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
369 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
370 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
Kevin Smith88809492015-03-16 14:58:21 +0000371 return 0;
Kevin Smith88809492015-03-16 14:58:21 +0000372 }
Mario Sixd6009d72017-01-11 16:00:54 +0100373 headersz = CONFIG_SYS_U_BOOT_OFFS;
Kevin Smith88809492015-03-16 14:58:21 +0000374#endif
375
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200376 /*
377 * The payload should be aligned on some reasonable
378 * boundary
379 */
380 return ALIGN_SUP(headersz, 4096);
381}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530382
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200383static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
384 int payloadsz)
385{
386 struct image_cfg_element *e, *binarye;
387 struct main_hdr_v1 *main_hdr;
388 size_t headersz;
Mario Six7497cd62017-01-11 16:00:55 +0100389 uint8_t *image, *cur;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200390 int hasext = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530391
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200392 /*
393 * Calculate the size of the header and the size of the
394 * payload
395 */
396 headersz = image_headersz_v1(params, &hasext);
397 if (headersz == 0)
398 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530399
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200400 image = malloc(headersz);
401 if (!image) {
402 fprintf(stderr, "Cannot allocate memory for image\n");
403 return NULL;
404 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530405
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200406 memset(image, 0, headersz);
407
Mario Six7497cd62017-01-11 16:00:55 +0100408 main_hdr = (struct main_hdr_v1 *)image;
409 cur = image + sizeof(struct main_hdr_v1);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200410
411 /* Fill the main header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100412 main_hdr->blocksize =
413 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
414 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200415 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
Mario Six7e407632017-01-11 16:00:53 +0100416 main_hdr->destaddr = cpu_to_le32(params->addr)
417 - sizeof(image_header_t);
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100418 main_hdr->execaddr = cpu_to_le32(params->ep);
419 main_hdr->srcaddr = cpu_to_le32(headersz);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200420 main_hdr->ext = hasext;
421 main_hdr->version = 1;
422 e = image_find_option(IMAGE_CFG_BOOT_FROM);
423 if (e)
424 main_hdr->blockid = e->bootfrom;
425 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
426 if (e)
427 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
428 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
429 if (e)
430 main_hdr->nandbadblklocation = e->nandbadblklocation;
Chris Packham883bf452016-11-09 22:07:45 +1300431 e = image_find_option(IMAGE_CFG_BAUDRATE);
432 if (e)
433 main_hdr->options = baudrate_to_option(e->baudrate);
Chris Packham1e0728a2016-11-09 22:21:45 +1300434 e = image_find_option(IMAGE_CFG_DEBUG);
435 if (e)
436 main_hdr->flags = e->debug ? 0x1 : 0;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200437
438 binarye = image_find_option(IMAGE_CFG_BINARY);
439 if (binarye) {
Mario Six7497cd62017-01-11 16:00:55 +0100440 struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100441 uint32_t *args;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200442 size_t binhdrsz;
443 struct stat s;
444 int argi;
445 FILE *bin;
Mario Six6f273632017-01-11 16:00:56 +0100446 int ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200447
448 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
449
450 bin = fopen(binarye->binary.file, "r");
451 if (!bin) {
452 fprintf(stderr, "Cannot open binary file %s\n",
453 binarye->binary.file);
454 return NULL;
455 }
456
457 fstat(fileno(bin), &s);
458
459 binhdrsz = sizeof(struct opt_hdr_v1) +
Reinhard Pfau5286c0d2015-11-29 15:52:14 +0100460 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200461 s.st_size;
Stefan Roesea4279a52015-10-28 07:53:58 +0100462
463 /*
464 * The size includes the binary image size, rounded
465 * up to a 4-byte boundary. Plus 4 bytes for the
466 * next-header byte and 3-byte alignment at the end.
467 */
468 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100469 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200470 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
471
472 cur += sizeof(struct opt_hdr_v1);
473
Mario Six7497cd62017-01-11 16:00:55 +0100474 args = (uint32_t *)cur;
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100475 *args = cpu_to_le32(binarye->binary.nargs);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200476 args++;
477 for (argi = 0; argi < binarye->binary.nargs; argi++)
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100478 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200479
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100480 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200481
482 ret = fread(cur, s.st_size, 1, bin);
483 if (ret != 1) {
484 fprintf(stderr,
485 "Could not read binary image %s\n",
486 binarye->binary.file);
487 return NULL;
488 }
489
490 fclose(bin);
491
Stefan Roesea4279a52015-10-28 07:53:58 +0100492 cur += ALIGN_SUP(s.st_size, 4);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200493
494 /*
495 * For now, we don't support more than one binary
496 * header, and no other header types are
497 * supported. So, the binary header is necessarily the
498 * last one
499 */
Stefan Roesea4279a52015-10-28 07:53:58 +0100500 *((uint32_t *)cur) = 0x00000000;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200501
502 cur += sizeof(uint32_t);
503 }
504
505 /* Calculate and set the header checksum */
506 main_hdr->checksum = image_checksum8(main_hdr, headersz);
507
508 *imagesz = headersz;
509 return image;
510}
511
512static int image_create_config_parse_oneline(char *line,
513 struct image_cfg_element *el)
514{
515 char *keyword, *saveptr;
516 char deliminiters[] = " \t";
517
518 keyword = strtok_r(line, deliminiters, &saveptr);
519 if (!strcmp(keyword, "VERSION")) {
520 char *value = strtok_r(NULL, deliminiters, &saveptr);
Mario Sixd6009d72017-01-11 16:00:54 +0100521
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200522 el->type = IMAGE_CFG_VERSION;
523 el->version = atoi(value);
524 } else if (!strcmp(keyword, "BOOT_FROM")) {
525 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200526 int ret = image_boot_mode_id(value);
Mario Sixd6009d72017-01-11 16:00:54 +0100527
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200528 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200529 fprintf(stderr,
530 "Invalid boot media '%s'\n", value);
531 return -1;
532 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200533 el->type = IMAGE_CFG_BOOT_FROM;
534 el->bootfrom = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200535 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
536 char *value = strtok_r(NULL, deliminiters, &saveptr);
Mario Sixd6009d72017-01-11 16:00:54 +0100537
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200538 el->type = IMAGE_CFG_NAND_BLKSZ;
539 el->nandblksz = strtoul(value, NULL, 16);
540 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
541 char *value = strtok_r(NULL, deliminiters, &saveptr);
Mario Sixd6009d72017-01-11 16:00:54 +0100542
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200543 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
544 el->nandbadblklocation =
545 strtoul(value, NULL, 16);
546 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
547 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200548 int ret = image_nand_ecc_mode_id(value);
Mario Sixd6009d72017-01-11 16:00:54 +0100549
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200550 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200551 fprintf(stderr,
552 "Invalid NAND ECC mode '%s'\n", value);
553 return -1;
554 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200555 el->type = IMAGE_CFG_NAND_ECC_MODE;
556 el->nandeccmode = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200557 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
558 char *value = strtok_r(NULL, deliminiters, &saveptr);
Mario Sixd6009d72017-01-11 16:00:54 +0100559
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200560 el->type = IMAGE_CFG_NAND_PAGESZ;
561 el->nandpagesz = strtoul(value, NULL, 16);
562 } else if (!strcmp(keyword, "BINARY")) {
563 char *value = strtok_r(NULL, deliminiters, &saveptr);
564 int argi = 0;
565
566 el->type = IMAGE_CFG_BINARY;
567 el->binary.file = strdup(value);
568 while (1) {
569 value = strtok_r(NULL, deliminiters, &saveptr);
570 if (!value)
571 break;
572 el->binary.args[argi] = strtoul(value, NULL, 16);
573 argi++;
574 if (argi >= BINARY_MAX_ARGS) {
575 fprintf(stderr,
576 "Too many argument for binary\n");
577 return -1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530578 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530579 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200580 el->binary.nargs = argi;
581 } else if (!strcmp(keyword, "DATA")) {
582 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
583 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
584
585 if (!value1 || !value2) {
586 fprintf(stderr,
587 "Invalid number of arguments for DATA\n");
588 return -1;
589 }
590
591 el->type = IMAGE_CFG_DATA;
592 el->regdata.raddr = strtoul(value1, NULL, 16);
593 el->regdata.rdata = strtoul(value2, NULL, 16);
Chris Packham883bf452016-11-09 22:07:45 +1300594 } else if (!strcmp(keyword, "BAUDRATE")) {
595 char *value = strtok_r(NULL, deliminiters, &saveptr);
596 el->type = IMAGE_CFG_BAUDRATE;
597 el->baudrate = strtoul(value, NULL, 10);
Chris Packham1e0728a2016-11-09 22:21:45 +1300598 } else if (!strcmp(keyword, "DEBUG")) {
599 char *value = strtok_r(NULL, deliminiters, &saveptr);
600 el->type = IMAGE_CFG_DEBUG;
601 el->debug = strtoul(value, NULL, 10);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200602 } else {
603 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530604 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530605
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200606 return 0;
607}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530608
609/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200610 * Parse the configuration file 'fcfg' into the array of configuration
611 * elements 'image_cfg', and return the number of configuration
612 * elements in 'cfgn'.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530613 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200614static int image_create_config_parse(FILE *fcfg)
615{
616 int ret;
617 int cfgi = 0;
618
619 /* Parse the configuration file */
620 while (!feof(fcfg)) {
621 char *line;
622 char buf[256];
623
624 /* Read the current line */
625 memset(buf, 0, sizeof(buf));
626 line = fgets(buf, sizeof(buf), fcfg);
627 if (!line)
628 break;
629
630 /* Ignore useless lines */
631 if (line[0] == '\n' || line[0] == '#')
632 continue;
633
634 /* Strip final newline */
635 if (line[strlen(line) - 1] == '\n')
636 line[strlen(line) - 1] = 0;
637
638 /* Parse the current line */
639 ret = image_create_config_parse_oneline(line,
640 &image_cfg[cfgi]);
641 if (ret)
642 return ret;
643
644 cfgi++;
645
646 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
647 fprintf(stderr,
648 "Too many configuration elements in .cfg file\n");
649 return -1;
650 }
651 }
652
653 cfgn = cfgi;
654 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530655}
656
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200657static int image_get_version(void)
658{
659 struct image_cfg_element *e;
660
661 e = image_find_option(IMAGE_CFG_VERSION);
662 if (!e)
663 return -1;
664
665 return e->version;
666}
667
668static int image_version_file(const char *input)
669{
670 FILE *fcfg;
671 int version;
672 int ret;
673
674 fcfg = fopen(input, "r");
675 if (!fcfg) {
676 fprintf(stderr, "Could not open input file %s\n", input);
677 return -1;
678 }
679
680 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
681 sizeof(struct image_cfg_element));
682 if (!image_cfg) {
683 fprintf(stderr, "Cannot allocate memory\n");
684 fclose(fcfg);
685 return -1;
686 }
687
688 memset(image_cfg, 0,
689 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
690 rewind(fcfg);
691
692 ret = image_create_config_parse(fcfg);
693 fclose(fcfg);
694 if (ret) {
695 free(image_cfg);
696 return -1;
697 }
698
699 version = image_get_version();
700 /* Fallback to version 0 is no version is provided in the cfg file */
701 if (version == -1)
702 version = 0;
703
704 free(image_cfg);
705
706 return version;
707}
708
709static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700710 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530711{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200712 FILE *fcfg;
713 void *image = NULL;
714 int version;
Łukasz Majewskif04dab42014-11-21 09:22:43 +0100715 size_t headersz = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530716 uint32_t checksum;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200717 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530718 int size;
719
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200720 fcfg = fopen(params->imagename, "r");
721 if (!fcfg) {
722 fprintf(stderr, "Could not open input file %s\n",
723 params->imagename);
724 exit(EXIT_FAILURE);
725 }
726
727 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
728 sizeof(struct image_cfg_element));
729 if (!image_cfg) {
730 fprintf(stderr, "Cannot allocate memory\n");
731 fclose(fcfg);
732 exit(EXIT_FAILURE);
733 }
734
735 memset(image_cfg, 0,
736 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
737 rewind(fcfg);
738
739 ret = image_create_config_parse(fcfg);
740 fclose(fcfg);
741 if (ret) {
742 free(image_cfg);
743 exit(EXIT_FAILURE);
744 }
745
Stefan Roese48676a32015-09-01 13:46:35 +0200746 /* The MVEBU BootROM does not allow non word aligned payloads */
747 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
748
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200749 version = image_get_version();
Stefan Roese933918c2014-10-28 11:32:24 +0100750 switch (version) {
751 /*
752 * Fallback to version 0 if no version is provided in the
753 * cfg file
754 */
755 case -1:
756 case 0:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200757 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100758 break;
759
760 case 1:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200761 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100762 break;
763
764 default:
765 fprintf(stderr, "Unsupported version %d\n", version);
766 free(image_cfg);
767 exit(EXIT_FAILURE);
768 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530769
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200770 if (!image) {
771 fprintf(stderr, "Could not create image\n");
772 free(image_cfg);
773 exit(EXIT_FAILURE);
774 }
775
776 free(image_cfg);
777
778 /* Build and add image checksum header */
Reinhard Pfau3efeaae2015-11-29 15:48:25 +0100779 checksum =
780 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200781 size = write(ifd, &checksum, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530782 if (size != sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200783 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530784 params->cmdname, size, params->imagefile);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200785 exit(EXIT_FAILURE);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530786 }
787
788 sbuf->st_size += sizeof(uint32_t);
789
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200790 /* Finally copy the header into the image area */
791 memcpy(ptr, image, headersz);
792
793 free(image);
794}
795
796static void kwbimage_print_header(const void *ptr)
797{
798 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
799
800 printf("Image Type: MVEBU Boot from %s Image\n",
801 image_boot_mode_name(mhdr->blockid));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200802 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100803 printf("Data Size: ");
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200804 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
805 printf("Load Address: %08x\n", mhdr->destaddr);
806 printf("Entry Point: %08x\n", mhdr->execaddr);
807}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530808
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200809static int kwbimage_check_image_types(uint8_t type)
810{
811 if (type == IH_TYPE_KWBIMAGE)
812 return EXIT_SUCCESS;
Mario Sixd6009d72017-01-11 16:00:54 +0100813
814 return EXIT_FAILURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530815}
816
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200817static int kwbimage_verify_header(unsigned char *ptr, int image_size,
818 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530819{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200820 struct main_hdr_v0 *main_hdr;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200821 uint8_t checksum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530822
Mario Six7497cd62017-01-11 16:00:55 +0100823 main_hdr = (struct main_hdr_v0 *)ptr;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200824 checksum = image_checksum8(ptr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100825 sizeof(struct main_hdr_v0)
826 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200827 if (checksum != main_hdr->checksum)
828 return -FDT_ERR_BADSTRUCTURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530829
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200830 /* Only version 0 extended header has checksum */
831 if (image_version((void *)ptr) == 0) {
Mario Six6f273632017-01-11 16:00:56 +0100832 struct ext_hdr_v0 *ext_hdr;
833
Mario Six7497cd62017-01-11 16:00:55 +0100834 ext_hdr = (struct ext_hdr_v0 *)
835 (ptr + sizeof(struct main_hdr_v0));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200836 checksum = image_checksum8(ext_hdr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100837 sizeof(struct ext_hdr_v0)
838 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200839 if (checksum != ext_hdr->checksum)
840 return -FDT_ERR_BADSTRUCTURE;
841 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530842
843 return 0;
844}
845
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200846static int kwbimage_generate(struct image_tool_params *params,
847 struct image_type_params *tparams)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530848{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200849 int alloc_len;
850 void *hdr;
851 int version = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530852
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200853 version = image_version_file(params->imagename);
854 if (version == 0) {
855 alloc_len = sizeof(struct main_hdr_v0) +
856 sizeof(struct ext_hdr_v0);
857 } else {
858 alloc_len = image_headersz_v1(params, NULL);
859 }
860
861 hdr = malloc(alloc_len);
862 if (!hdr) {
863 fprintf(stderr, "%s: malloc return failure: %s\n",
864 params->cmdname, strerror(errno));
865 exit(EXIT_FAILURE);
866 }
867
868 memset(hdr, 0, alloc_len);
869 tparams->header_size = alloc_len;
870 tparams->hdr = hdr;
871
Stefan Roeseda43fd32015-11-24 09:14:59 +0100872 /*
873 * The resulting image needs to be 4-byte aligned. At least
874 * the Marvell hdrparser tool complains if its unaligned.
875 * By returning 1 here in this function, called via
876 * tparams->vrec_header() in mkimage.c, mkimage will
877 * automatically pad the the resulting image to a 4-byte
878 * size if necessary.
879 */
880 return 1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530881}
882
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200883/*
884 * Report Error if xflag is set in addition to default
885 */
886static int kwbimage_check_params(struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530887{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200888 if (!strlen(params->imagename)) {
Mario Sixd6009d72017-01-11 16:00:54 +0100889 char *msg = "Configuration file for kwbimage creation omitted";
890
891 fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200892 return CFG_INVALID;
893 }
894
895 return (params->dflag && (params->fflag || params->lflag)) ||
896 (params->fflag && (params->dflag || params->lflag)) ||
897 (params->lflag && (params->dflag || params->fflag)) ||
898 (params->xflag) || !(strlen(params->imagename));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530899}
900
901/*
902 * kwbimage type parameters definition
903 */
Guilherme Maciel Ferreira28be1cf2015-01-15 02:48:07 -0200904U_BOOT_IMAGE_TYPE(
905 kwbimage,
906 "Marvell MVEBU Boot Image support",
907 0,
908 NULL,
909 kwbimage_check_params,
910 kwbimage_verify_header,
911 kwbimage_print_header,
912 kwbimage_set_header,
913 NULL,
914 kwbimage_check_image_types,
915 NULL,
916 kwbimage_generate
917);