blob: d33f1b6974f7cbfdbcacd0adf37096b448d47813 [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,
71 } type;
72 union {
73 unsigned int version;
74 unsigned int bootfrom;
75 struct {
76 const char *file;
77 unsigned int args[BINARY_MAX_ARGS];
78 unsigned int nargs;
79 } binary;
80 const char *payload;
81 unsigned int dstaddr;
82 unsigned int execaddr;
83 unsigned int nandblksz;
84 unsigned int nandbadblklocation;
85 unsigned int nandeccmode;
86 unsigned int nandpagesz;
87 struct ext_hdr_v0_reg regdata;
88 };
89};
90
91#define IMAGE_CFG_ELEMENT_MAX 256
Prafulla Wadaskar07329412009-09-07 15:05:02 +053092
93/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +020094 * Utility functions to manipulate boot mode and ecc modes (convert
95 * them back and forth between description strings and the
96 * corresponding numerical identifiers).
97 */
98
99static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530100{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200101 int i;
102 for (i = 0; boot_modes[i].name; i++)
103 if (boot_modes[i].id == id)
104 return boot_modes[i].name;
105 return NULL;
106}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530107
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200108int image_boot_mode_id(const char *boot_mode_name)
109{
110 int i;
111 for (i = 0; boot_modes[i].name; i++)
112 if (!strcmp(boot_modes[i].name, boot_mode_name))
113 return boot_modes[i].id;
114
115 return -1;
116}
117
118int image_nand_ecc_mode_id(const char *nand_ecc_mode_name)
119{
120 int i;
121 for (i = 0; nand_ecc_modes[i].name; i++)
122 if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name))
123 return nand_ecc_modes[i].id;
124 return -1;
125}
126
127static struct image_cfg_element *
128image_find_option(unsigned int optiontype)
129{
130 int i;
131
132 for (i = 0; i < cfgn; i++) {
133 if (image_cfg[i].type == optiontype)
134 return &image_cfg[i];
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530135 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200136
137 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530138}
139
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200140static unsigned int
141image_count_options(unsigned int optiontype)
142{
143 int i;
144 unsigned int count = 0;
145
146 for (i = 0; i < cfgn; i++)
147 if (image_cfg[i].type == optiontype)
148 count++;
149
150 return count;
151}
152
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530153/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200154 * Compute a 8-bit checksum of a memory area. This algorithm follows
155 * the requirements of the Marvell SoC BootROM specifications.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530156 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200157static uint8_t image_checksum8(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530158{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200159 uint8_t csum = 0;
160 uint8_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530161
162 /* check len and return zero checksum if invalid */
163 if (!len)
164 return 0;
165
166 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200167 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530168 p++;
169 } while (--len);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200170
171 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530172}
173
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200174static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530175{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200176 uint32_t csum = 0;
177 uint32_t *p = start;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530178
179 /* check len and return zero checksum if invalid */
180 if (!len)
181 return 0;
182
183 if (len % sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200184 fprintf(stderr, "Length %d is not in multiple of %zu\n",
185 len, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530186 return 0;
187 }
188
189 do {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200190 csum += *p;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530191 p++;
192 len -= sizeof(uint32_t);
193 } while (len > 0);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200194
195 return csum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530196}
197
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200198static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
199 int payloadsz)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530200{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200201 struct image_cfg_element *e;
202 size_t headersz;
203 struct main_hdr_v0 *main_hdr;
204 struct ext_hdr_v0 *ext_hdr;
205 void *image;
206 int has_ext = 0;
207
208 /*
209 * Calculate the size of the header and the size of the
210 * payload
211 */
212 headersz = sizeof(struct main_hdr_v0);
213
214 if (image_count_options(IMAGE_CFG_DATA) > 0) {
215 has_ext = 1;
216 headersz += sizeof(struct ext_hdr_v0);
217 }
218
219 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
220 fprintf(stderr, "More than one payload, not possible\n");
221 return NULL;
222 }
223
224 image = malloc(headersz);
225 if (!image) {
226 fprintf(stderr, "Cannot allocate memory for image\n");
227 return NULL;
228 }
229
230 memset(image, 0, headersz);
231
232 main_hdr = image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530233
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200234 /* Fill in the main header */
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100235 main_hdr->blocksize = payloadsz + sizeof(uint32_t) - headersz;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200236 main_hdr->srcaddr = headersz;
237 main_hdr->ext = has_ext;
238 main_hdr->destaddr = params->addr;
239 main_hdr->execaddr = params->ep;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530240
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200241 e = image_find_option(IMAGE_CFG_BOOT_FROM);
242 if (e)
243 main_hdr->blockid = e->bootfrom;
244 e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
245 if (e)
246 main_hdr->nandeccmode = e->nandeccmode;
247 e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
248 if (e)
249 main_hdr->nandpagesize = e->nandpagesz;
250 main_hdr->checksum = image_checksum8(image,
251 sizeof(struct main_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530252
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200253 /* Generate the ext header */
254 if (has_ext) {
255 int cfgi, datai;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530256
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200257 ext_hdr = image + sizeof(struct main_hdr_v0);
258 ext_hdr->offset = 0x40;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530259
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200260 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
261 e = &image_cfg[cfgi];
262 if (e->type != IMAGE_CFG_DATA)
263 continue;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530264
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200265 ext_hdr->rcfg[datai].raddr = e->regdata.raddr;
266 ext_hdr->rcfg[datai].rdata = e->regdata.rdata;
267 datai++;
268 }
269
270 ext_hdr->checksum = image_checksum8(ext_hdr,
271 sizeof(struct ext_hdr_v0));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530272 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530273
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200274 *imagesz = headersz;
275 return image;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530276}
277
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200278static size_t image_headersz_v1(struct image_tool_params *params,
279 int *hasext)
280{
281 struct image_cfg_element *binarye;
282 size_t headersz;
283 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530284
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200285 /*
286 * Calculate the size of the header and the size of the
287 * payload
288 */
289 headersz = sizeof(struct main_hdr_v1);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530290
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200291 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
292 fprintf(stderr, "More than one binary blob, not supported\n");
293 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530294 }
295
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200296 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
297 fprintf(stderr, "More than one payload, not possible\n");
298 return 0;
299 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530300
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200301 binarye = image_find_option(IMAGE_CFG_BINARY);
302 if (binarye) {
303 struct stat s;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530304
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200305 ret = stat(binarye->binary.file, &s);
306 if (ret < 0) {
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200307 char cwd[PATH_MAX];
308 char *dir = cwd;
309
310 memset(cwd, 0, sizeof(cwd));
311 if (!getcwd(cwd, sizeof(cwd))) {
312 dir = "current working directory";
313 perror("getcwd() failed");
314 }
315
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200316 fprintf(stderr,
317 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
318 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
319 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
Andreas Bießmann7abec5b2014-10-24 23:39:11 +0200320 binarye->binary.file, dir);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200321 return 0;
322 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530323
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200324 headersz += s.st_size +
325 binarye->binary.nargs * sizeof(unsigned int);
326 if (hasext)
327 *hasext = 1;
328 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530329
Stefan Roese69e9dde2015-07-20 11:20:38 +0200330#if defined(CONFIG_SYS_U_BOOT_OFFS)
331 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
Kevin Smith88809492015-03-16 14:58:21 +0000332 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
Stefan Roese69e9dde2015-07-20 11:20:38 +0200333 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
334 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
335 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
Kevin Smith88809492015-03-16 14:58:21 +0000336 return 0;
337 } else {
Stefan Roese69e9dde2015-07-20 11:20:38 +0200338 headersz = CONFIG_SYS_U_BOOT_OFFS;
Kevin Smith88809492015-03-16 14:58:21 +0000339 }
340#endif
341
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200342 /*
343 * The payload should be aligned on some reasonable
344 * boundary
345 */
346 return ALIGN_SUP(headersz, 4096);
347}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530348
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200349static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
350 int payloadsz)
351{
352 struct image_cfg_element *e, *binarye;
353 struct main_hdr_v1 *main_hdr;
354 size_t headersz;
355 void *image, *cur;
356 int hasext = 0;
357 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530358
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200359 /*
360 * Calculate the size of the header and the size of the
361 * payload
362 */
363 headersz = image_headersz_v1(params, &hasext);
364 if (headersz == 0)
365 return NULL;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530366
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200367 image = malloc(headersz);
368 if (!image) {
369 fprintf(stderr, "Cannot allocate memory for image\n");
370 return NULL;
371 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530372
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200373 memset(image, 0, headersz);
374
375 cur = main_hdr = image;
376 cur += sizeof(struct main_hdr_v1);
377
378 /* Fill the main header */
379 main_hdr->blocksize = payloadsz - headersz + sizeof(uint32_t);
380 main_hdr->headersz_lsb = headersz & 0xFFFF;
381 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
382 main_hdr->destaddr = params->addr;
383 main_hdr->execaddr = params->ep;
384 main_hdr->srcaddr = headersz;
385 main_hdr->ext = hasext;
386 main_hdr->version = 1;
387 e = image_find_option(IMAGE_CFG_BOOT_FROM);
388 if (e)
389 main_hdr->blockid = e->bootfrom;
390 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
391 if (e)
392 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
393 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
394 if (e)
395 main_hdr->nandbadblklocation = e->nandbadblklocation;
396
397 binarye = image_find_option(IMAGE_CFG_BINARY);
398 if (binarye) {
399 struct opt_hdr_v1 *hdr = cur;
400 unsigned int *args;
401 size_t binhdrsz;
402 struct stat s;
403 int argi;
404 FILE *bin;
405
406 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
407
408 bin = fopen(binarye->binary.file, "r");
409 if (!bin) {
410 fprintf(stderr, "Cannot open binary file %s\n",
411 binarye->binary.file);
412 return NULL;
413 }
414
415 fstat(fileno(bin), &s);
416
417 binhdrsz = sizeof(struct opt_hdr_v1) +
418 (binarye->binary.nargs + 1) * sizeof(unsigned int) +
419 s.st_size;
Chris Packham3a1fc232015-02-23 11:25:20 +1300420 binhdrsz = ALIGN_SUP(binhdrsz, 32);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200421 hdr->headersz_lsb = binhdrsz & 0xFFFF;
422 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
423
424 cur += sizeof(struct opt_hdr_v1);
425
426 args = cur;
427 *args = binarye->binary.nargs;
428 args++;
429 for (argi = 0; argi < binarye->binary.nargs; argi++)
430 args[argi] = binarye->binary.args[argi];
431
432 cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
433
434 ret = fread(cur, s.st_size, 1, bin);
435 if (ret != 1) {
436 fprintf(stderr,
437 "Could not read binary image %s\n",
438 binarye->binary.file);
439 return NULL;
440 }
441
442 fclose(bin);
443
444 cur += s.st_size;
445
446 /*
447 * For now, we don't support more than one binary
448 * header, and no other header types are
449 * supported. So, the binary header is necessarily the
450 * last one
451 */
452 *((unsigned char *)cur) = 0;
453
454 cur += sizeof(uint32_t);
455 }
456
457 /* Calculate and set the header checksum */
458 main_hdr->checksum = image_checksum8(main_hdr, headersz);
459
460 *imagesz = headersz;
461 return image;
462}
463
464static int image_create_config_parse_oneline(char *line,
465 struct image_cfg_element *el)
466{
467 char *keyword, *saveptr;
468 char deliminiters[] = " \t";
469
470 keyword = strtok_r(line, deliminiters, &saveptr);
471 if (!strcmp(keyword, "VERSION")) {
472 char *value = strtok_r(NULL, deliminiters, &saveptr);
473 el->type = IMAGE_CFG_VERSION;
474 el->version = atoi(value);
475 } else if (!strcmp(keyword, "BOOT_FROM")) {
476 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200477 int ret = image_boot_mode_id(value);
478 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200479 fprintf(stderr,
480 "Invalid boot media '%s'\n", value);
481 return -1;
482 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200483 el->type = IMAGE_CFG_BOOT_FROM;
484 el->bootfrom = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200485 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
486 char *value = strtok_r(NULL, deliminiters, &saveptr);
487 el->type = IMAGE_CFG_NAND_BLKSZ;
488 el->nandblksz = strtoul(value, NULL, 16);
489 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
490 char *value = strtok_r(NULL, deliminiters, &saveptr);
491 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
492 el->nandbadblklocation =
493 strtoul(value, NULL, 16);
494 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
495 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200496 int ret = image_nand_ecc_mode_id(value);
497 if (ret < 0) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200498 fprintf(stderr,
499 "Invalid NAND ECC mode '%s'\n", value);
500 return -1;
501 }
Andreas Bießmann4c40e352014-10-24 23:25:52 +0200502 el->type = IMAGE_CFG_NAND_ECC_MODE;
503 el->nandeccmode = ret;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200504 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
505 char *value = strtok_r(NULL, deliminiters, &saveptr);
506 el->type = IMAGE_CFG_NAND_PAGESZ;
507 el->nandpagesz = strtoul(value, NULL, 16);
508 } else if (!strcmp(keyword, "BINARY")) {
509 char *value = strtok_r(NULL, deliminiters, &saveptr);
510 int argi = 0;
511
512 el->type = IMAGE_CFG_BINARY;
513 el->binary.file = strdup(value);
514 while (1) {
515 value = strtok_r(NULL, deliminiters, &saveptr);
516 if (!value)
517 break;
518 el->binary.args[argi] = strtoul(value, NULL, 16);
519 argi++;
520 if (argi >= BINARY_MAX_ARGS) {
521 fprintf(stderr,
522 "Too many argument for binary\n");
523 return -1;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530524 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530525 }
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200526 el->binary.nargs = argi;
527 } else if (!strcmp(keyword, "DATA")) {
528 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
529 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
530
531 if (!value1 || !value2) {
532 fprintf(stderr,
533 "Invalid number of arguments for DATA\n");
534 return -1;
535 }
536
537 el->type = IMAGE_CFG_DATA;
538 el->regdata.raddr = strtoul(value1, NULL, 16);
539 el->regdata.rdata = strtoul(value2, NULL, 16);
540 } else {
541 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530542 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530543
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200544 return 0;
545}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530546
547/*
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200548 * Parse the configuration file 'fcfg' into the array of configuration
549 * elements 'image_cfg', and return the number of configuration
550 * elements in 'cfgn'.
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530551 */
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200552static int image_create_config_parse(FILE *fcfg)
553{
554 int ret;
555 int cfgi = 0;
556
557 /* Parse the configuration file */
558 while (!feof(fcfg)) {
559 char *line;
560 char buf[256];
561
562 /* Read the current line */
563 memset(buf, 0, sizeof(buf));
564 line = fgets(buf, sizeof(buf), fcfg);
565 if (!line)
566 break;
567
568 /* Ignore useless lines */
569 if (line[0] == '\n' || line[0] == '#')
570 continue;
571
572 /* Strip final newline */
573 if (line[strlen(line) - 1] == '\n')
574 line[strlen(line) - 1] = 0;
575
576 /* Parse the current line */
577 ret = image_create_config_parse_oneline(line,
578 &image_cfg[cfgi]);
579 if (ret)
580 return ret;
581
582 cfgi++;
583
584 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
585 fprintf(stderr,
586 "Too many configuration elements in .cfg file\n");
587 return -1;
588 }
589 }
590
591 cfgn = cfgi;
592 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530593}
594
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200595static int image_get_version(void)
596{
597 struct image_cfg_element *e;
598
599 e = image_find_option(IMAGE_CFG_VERSION);
600 if (!e)
601 return -1;
602
603 return e->version;
604}
605
606static int image_version_file(const char *input)
607{
608 FILE *fcfg;
609 int version;
610 int ret;
611
612 fcfg = fopen(input, "r");
613 if (!fcfg) {
614 fprintf(stderr, "Could not open input file %s\n", input);
615 return -1;
616 }
617
618 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
619 sizeof(struct image_cfg_element));
620 if (!image_cfg) {
621 fprintf(stderr, "Cannot allocate memory\n");
622 fclose(fcfg);
623 return -1;
624 }
625
626 memset(image_cfg, 0,
627 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
628 rewind(fcfg);
629
630 ret = image_create_config_parse(fcfg);
631 fclose(fcfg);
632 if (ret) {
633 free(image_cfg);
634 return -1;
635 }
636
637 version = image_get_version();
638 /* Fallback to version 0 is no version is provided in the cfg file */
639 if (version == -1)
640 version = 0;
641
642 free(image_cfg);
643
644 return version;
645}
646
647static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
Guilherme Maciel Ferreira8ed4d1c2013-12-01 12:43:10 -0700648 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530649{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200650 FILE *fcfg;
651 void *image = NULL;
652 int version;
Łukasz Majewskif04dab42014-11-21 09:22:43 +0100653 size_t headersz = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530654 uint32_t checksum;
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200655 int ret;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530656 int size;
657
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200658 fcfg = fopen(params->imagename, "r");
659 if (!fcfg) {
660 fprintf(stderr, "Could not open input file %s\n",
661 params->imagename);
662 exit(EXIT_FAILURE);
663 }
664
665 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
666 sizeof(struct image_cfg_element));
667 if (!image_cfg) {
668 fprintf(stderr, "Cannot allocate memory\n");
669 fclose(fcfg);
670 exit(EXIT_FAILURE);
671 }
672
673 memset(image_cfg, 0,
674 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
675 rewind(fcfg);
676
677 ret = image_create_config_parse(fcfg);
678 fclose(fcfg);
679 if (ret) {
680 free(image_cfg);
681 exit(EXIT_FAILURE);
682 }
683
Stefan Roese48676a32015-09-01 13:46:35 +0200684 /* The MVEBU BootROM does not allow non word aligned payloads */
685 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
686
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200687 version = image_get_version();
Stefan Roese933918c2014-10-28 11:32:24 +0100688 switch (version) {
689 /*
690 * Fallback to version 0 if no version is provided in the
691 * cfg file
692 */
693 case -1:
694 case 0:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200695 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100696 break;
697
698 case 1:
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200699 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese933918c2014-10-28 11:32:24 +0100700 break;
701
702 default:
703 fprintf(stderr, "Unsupported version %d\n", version);
704 free(image_cfg);
705 exit(EXIT_FAILURE);
706 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530707
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200708 if (!image) {
709 fprintf(stderr, "Could not create image\n");
710 free(image_cfg);
711 exit(EXIT_FAILURE);
712 }
713
714 free(image_cfg);
715
716 /* Build and add image checksum header */
717 checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
718 size = write(ifd, &checksum, sizeof(uint32_t));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530719 if (size != sizeof(uint32_t)) {
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200720 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530721 params->cmdname, size, params->imagefile);
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200722 exit(EXIT_FAILURE);
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530723 }
724
725 sbuf->st_size += sizeof(uint32_t);
726
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200727 /* Finally copy the header into the image area */
728 memcpy(ptr, image, headersz);
729
730 free(image);
731}
732
733static void kwbimage_print_header(const void *ptr)
734{
735 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
736
737 printf("Image Type: MVEBU Boot from %s Image\n",
738 image_boot_mode_name(mhdr->blockid));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200739 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100740 printf("Data Size: ");
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200741 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
742 printf("Load Address: %08x\n", mhdr->destaddr);
743 printf("Entry Point: %08x\n", mhdr->execaddr);
744}
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530745
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200746static int kwbimage_check_image_types(uint8_t type)
747{
748 if (type == IH_TYPE_KWBIMAGE)
749 return EXIT_SUCCESS;
750 else
751 return EXIT_FAILURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530752}
753
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200754static int kwbimage_verify_header(unsigned char *ptr, int image_size,
755 struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530756{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200757 struct main_hdr_v0 *main_hdr;
758 struct ext_hdr_v0 *ext_hdr;
759 uint8_t checksum;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530760
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200761 main_hdr = (void *)ptr;
762 checksum = image_checksum8(ptr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100763 sizeof(struct main_hdr_v0)
764 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200765 if (checksum != main_hdr->checksum)
766 return -FDT_ERR_BADSTRUCTURE;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530767
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200768 /* Only version 0 extended header has checksum */
769 if (image_version((void *)ptr) == 0) {
770 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
771 checksum = image_checksum8(ext_hdr,
Gerald Kerma8f9e5832014-10-31 01:03:27 +0100772 sizeof(struct ext_hdr_v0)
773 - sizeof(uint8_t));
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200774 if (checksum != ext_hdr->checksum)
775 return -FDT_ERR_BADSTRUCTURE;
776 }
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530777
778 return 0;
779}
780
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200781static int kwbimage_generate(struct image_tool_params *params,
782 struct image_type_params *tparams)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530783{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200784 int alloc_len;
785 void *hdr;
786 int version = 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530787
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200788 version = image_version_file(params->imagename);
789 if (version == 0) {
790 alloc_len = sizeof(struct main_hdr_v0) +
791 sizeof(struct ext_hdr_v0);
792 } else {
793 alloc_len = image_headersz_v1(params, NULL);
794 }
795
796 hdr = malloc(alloc_len);
797 if (!hdr) {
798 fprintf(stderr, "%s: malloc return failure: %s\n",
799 params->cmdname, strerror(errno));
800 exit(EXIT_FAILURE);
801 }
802
803 memset(hdr, 0, alloc_len);
804 tparams->header_size = alloc_len;
805 tparams->hdr = hdr;
806
807 return 0;
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530808}
809
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200810/*
811 * Report Error if xflag is set in addition to default
812 */
813static int kwbimage_check_params(struct image_tool_params *params)
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530814{
Stefan Roese3b8b19d2014-10-22 12:13:23 +0200815 if (!strlen(params->imagename)) {
816 fprintf(stderr, "Error:%s - Configuration file not specified, "
817 "it is needed for kwbimage generation\n",
818 params->cmdname);
819 return CFG_INVALID;
820 }
821
822 return (params->dflag && (params->fflag || params->lflag)) ||
823 (params->fflag && (params->dflag || params->lflag)) ||
824 (params->lflag && (params->dflag || params->fflag)) ||
825 (params->xflag) || !(strlen(params->imagename));
Prafulla Wadaskar07329412009-09-07 15:05:02 +0530826}
827
828/*
829 * kwbimage type parameters definition
830 */
Guilherme Maciel Ferreira28be1cf2015-01-15 02:48:07 -0200831U_BOOT_IMAGE_TYPE(
832 kwbimage,
833 "Marvell MVEBU Boot Image support",
834 0,
835 NULL,
836 kwbimage_check_params,
837 kwbimage_verify_header,
838 kwbimage_print_header,
839 kwbimage_set_header,
840 NULL,
841 kwbimage_check_image_types,
842 NULL,
843 kwbimage_generate
844);