blob: 5f6d91c486559e5982333b9e2b50d46183817f6b [file] [log] [blame]
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +05301/*
Stefan Roese4acd2d22014-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 Wadaskaraa0c7a82009-09-07 15:05:02 +05307 *
Wolfgang Denk1a459662013-07-08 09:37:19 +02008 * SPDX-License-Identifier: GPL-2.0+
Stefan Roese4acd2d22014-10-22 12:13:23 +02009 *
10 * Not implemented: support for the register headers and secure
11 * headers in v1 images
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +053012 */
13
Guilherme Maciel Ferreiraf86ed6a2013-12-01 12:43:10 -070014#include "imagetool.h"
Andreas Bießmanne5f1a582014-10-24 23:39:11 +020015#include <limits.h>
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +053016#include <image.h>
Stefan Roese4acd2d22014-10-22 12:13:23 +020017#include <stdint.h>
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +053018#include "kwbimage.h"
19
Stefan Roese4acd2d22014-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;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +053026};
27
Stefan Roese4acd2d22014-10-22 12:13:23 +020028struct boot_mode boot_modes[] = {
29 { 0x4D, "i2c" },
30 { 0x5A, "spi" },
31 { 0x8B, "nand" },
32 { 0x78, "sata" },
33 { 0x9C, "pex" },
34 { 0x69, "uart" },
Stefan Roese1bbe63c2015-07-20 11:20:37 +020035 { 0xAE, "sdio" },
Stefan Roese4acd2d22014-10-22 12:13:23 +020036 {},
37};
38
39struct 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 Wadaskaraa0c7a82009-09-07 15:05:02 +053092
93/*
Stefan Roese4acd2d22014-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).
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +053097 */
Stefan Roese4acd2d22014-10-22 12:13:23 +020098
99static const char *image_boot_mode_name(unsigned int id)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530100{
Stefan Roese4acd2d22014-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}
107
108int 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];
135 }
136
137 return NULL;
138}
139
140static 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
153/*
154 * Compute a 8-bit checksum of a memory area. This algorithm follows
155 * the requirements of the Marvell SoC BootROM specifications.
156 */
157static uint8_t image_checksum8(void *start, uint32_t len)
158{
159 uint8_t csum = 0;
160 uint8_t *p = start;
Prafulla Wadaskaraa0c7a82009-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 Roese4acd2d22014-10-22 12:13:23 +0200167 csum += *p;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530168 p++;
169 } while (--len);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200170
171 return csum;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530172}
173
Stefan Roese4acd2d22014-10-22 12:13:23 +0200174static uint32_t image_checksum32(void *start, uint32_t len)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530175{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200176 uint32_t csum = 0;
177 uint32_t *p = start;
Prafulla Wadaskaraa0c7a82009-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 Roese4acd2d22014-10-22 12:13:23 +0200184 fprintf(stderr, "Length %d is not in multiple of %zu\n",
185 len, sizeof(uint32_t));
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530186 return 0;
187 }
188
189 do {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200190 csum += *p;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530191 p++;
192 len -= sizeof(uint32_t);
193 } while (len > 0);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200194
195 return csum;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530196}
197
Stefan Roese4acd2d22014-10-22 12:13:23 +0200198static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
199 int payloadsz)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530200{
Stefan Roese4acd2d22014-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;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530207
Stefan Roese4acd2d22014-10-22 12:13:23 +0200208 /*
209 * Calculate the size of the header and the size of the
210 * payload
211 */
212 headersz = sizeof(struct main_hdr_v0);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530213
Stefan Roese4acd2d22014-10-22 12:13:23 +0200214 if (image_count_options(IMAGE_CFG_DATA) > 0) {
215 has_ext = 1;
216 headersz += sizeof(struct ext_hdr_v0);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530217 }
218
Stefan Roese4acd2d22014-10-22 12:13:23 +0200219 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
220 fprintf(stderr, "More than one payload, not possible\n");
221 return NULL;
222 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530223
Stefan Roese4acd2d22014-10-22 12:13:23 +0200224 image = malloc(headersz);
225 if (!image) {
226 fprintf(stderr, "Cannot allocate memory for image\n");
227 return NULL;
228 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530229
Stefan Roese4acd2d22014-10-22 12:13:23 +0200230 memset(image, 0, headersz);
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530231
Stefan Roese4acd2d22014-10-22 12:13:23 +0200232 main_hdr = image;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530233
Stefan Roese4acd2d22014-10-22 12:13:23 +0200234 /* Fill in the main header */
Gerald Kerma26f195c2014-10-31 01:03:27 +0100235 main_hdr->blocksize = payloadsz + sizeof(uint32_t) - headersz;
Stefan Roese4acd2d22014-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 Wadaskaraa0c7a82009-09-07 15:05:02 +0530240
Stefan Roese4acd2d22014-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 Wadaskaraa0c7a82009-09-07 15:05:02 +0530252
Stefan Roese4acd2d22014-10-22 12:13:23 +0200253 /* Generate the ext header */
254 if (has_ext) {
255 int cfgi, datai;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530256
Stefan Roese4acd2d22014-10-22 12:13:23 +0200257 ext_hdr = image + sizeof(struct main_hdr_v0);
258 ext_hdr->offset = 0x40;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530259
Stefan Roese4acd2d22014-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;
264
265 ext_hdr->rcfg[datai].raddr = e->regdata.raddr;
266 ext_hdr->rcfg[datai].rdata = e->regdata.rdata;
267 datai++;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530268 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530269
Stefan Roese4acd2d22014-10-22 12:13:23 +0200270 ext_hdr->checksum = image_checksum8(ext_hdr,
271 sizeof(struct ext_hdr_v0));
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530272 }
273
Stefan Roese4acd2d22014-10-22 12:13:23 +0200274 *imagesz = headersz;
275 return image;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530276}
277
Stefan Roese4acd2d22014-10-22 12:13:23 +0200278static size_t image_headersz_v1(struct image_tool_params *params,
279 int *hasext)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530280{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200281 struct image_cfg_element *binarye;
282 size_t headersz;
283 int ret;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530284
Stefan Roese4acd2d22014-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 Wadaskaraa0c7a82009-09-07 15:05:02 +0530290
Stefan Roese4acd2d22014-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;
294 }
295
296 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
297 fprintf(stderr, "More than one payload, not possible\n");
298 return 0;
299 }
300
301 binarye = image_find_option(IMAGE_CFG_BINARY);
302 if (binarye) {
303 struct stat s;
304
305 ret = stat(binarye->binary.file, &s);
306 if (ret < 0) {
Andreas Bießmanne5f1a582014-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 Roese4acd2d22014-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ßmanne5f1a582014-10-24 23:39:11 +0200320 binarye->binary.file, dir);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200321 return 0;
322 }
323
324 headersz += s.st_size +
325 binarye->binary.nargs * sizeof(unsigned int);
326 if (hasext)
327 *hasext = 1;
328 }
329
Stefan Roese7ddf8cf2015-07-20 11:20:38 +0200330#if defined(CONFIG_SYS_U_BOOT_OFFS)
331 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
Kevin Smitha0aad122015-03-16 14:58:21 +0000332 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
Stefan Roese7ddf8cf2015-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 Smitha0aad122015-03-16 14:58:21 +0000336 return 0;
337 } else {
Stefan Roese7ddf8cf2015-07-20 11:20:38 +0200338 headersz = CONFIG_SYS_U_BOOT_OFFS;
Kevin Smitha0aad122015-03-16 14:58:21 +0000339 }
340#endif
341
Stefan Roese4acd2d22014-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}
348
349static 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;
358
359 /*
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;
366
367 image = malloc(headersz);
368 if (!image) {
369 fprintf(stderr, "Cannot allocate memory for image\n");
370 return NULL;
371 }
372
373 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;
Stefan Roeseea8b6872015-10-28 07:53:58 +0100420
421 /*
422 * The size includes the binary image size, rounded
423 * up to a 4-byte boundary. Plus 4 bytes for the
424 * next-header byte and 3-byte alignment at the end.
425 */
426 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200427 hdr->headersz_lsb = binhdrsz & 0xFFFF;
428 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
429
430 cur += sizeof(struct opt_hdr_v1);
431
432 args = cur;
433 *args = binarye->binary.nargs;
434 args++;
435 for (argi = 0; argi < binarye->binary.nargs; argi++)
436 args[argi] = binarye->binary.args[argi];
437
438 cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
439
440 ret = fread(cur, s.st_size, 1, bin);
441 if (ret != 1) {
442 fprintf(stderr,
443 "Could not read binary image %s\n",
444 binarye->binary.file);
445 return NULL;
446 }
447
448 fclose(bin);
449
Stefan Roeseea8b6872015-10-28 07:53:58 +0100450 cur += ALIGN_SUP(s.st_size, 4);
Stefan Roese4acd2d22014-10-22 12:13:23 +0200451
452 /*
453 * For now, we don't support more than one binary
454 * header, and no other header types are
455 * supported. So, the binary header is necessarily the
456 * last one
457 */
Stefan Roeseea8b6872015-10-28 07:53:58 +0100458 *((uint32_t *)cur) = 0x00000000;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200459
460 cur += sizeof(uint32_t);
461 }
462
463 /* Calculate and set the header checksum */
464 main_hdr->checksum = image_checksum8(main_hdr, headersz);
465
466 *imagesz = headersz;
467 return image;
468}
469
470static int image_create_config_parse_oneline(char *line,
471 struct image_cfg_element *el)
472{
473 char *keyword, *saveptr;
474 char deliminiters[] = " \t";
475
476 keyword = strtok_r(line, deliminiters, &saveptr);
477 if (!strcmp(keyword, "VERSION")) {
478 char *value = strtok_r(NULL, deliminiters, &saveptr);
479 el->type = IMAGE_CFG_VERSION;
480 el->version = atoi(value);
481 } else if (!strcmp(keyword, "BOOT_FROM")) {
482 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200483 int ret = image_boot_mode_id(value);
484 if (ret < 0) {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200485 fprintf(stderr,
486 "Invalid boot media '%s'\n", value);
487 return -1;
488 }
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200489 el->type = IMAGE_CFG_BOOT_FROM;
490 el->bootfrom = ret;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200491 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
492 char *value = strtok_r(NULL, deliminiters, &saveptr);
493 el->type = IMAGE_CFG_NAND_BLKSZ;
494 el->nandblksz = strtoul(value, NULL, 16);
495 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
496 char *value = strtok_r(NULL, deliminiters, &saveptr);
497 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
498 el->nandbadblklocation =
499 strtoul(value, NULL, 16);
500 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
501 char *value = strtok_r(NULL, deliminiters, &saveptr);
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200502 int ret = image_nand_ecc_mode_id(value);
503 if (ret < 0) {
Stefan Roese4acd2d22014-10-22 12:13:23 +0200504 fprintf(stderr,
505 "Invalid NAND ECC mode '%s'\n", value);
506 return -1;
507 }
Andreas Bießmannf411b8f2014-10-24 23:25:52 +0200508 el->type = IMAGE_CFG_NAND_ECC_MODE;
509 el->nandeccmode = ret;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200510 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
511 char *value = strtok_r(NULL, deliminiters, &saveptr);
512 el->type = IMAGE_CFG_NAND_PAGESZ;
513 el->nandpagesz = strtoul(value, NULL, 16);
514 } else if (!strcmp(keyword, "BINARY")) {
515 char *value = strtok_r(NULL, deliminiters, &saveptr);
516 int argi = 0;
517
518 el->type = IMAGE_CFG_BINARY;
519 el->binary.file = strdup(value);
520 while (1) {
521 value = strtok_r(NULL, deliminiters, &saveptr);
522 if (!value)
523 break;
524 el->binary.args[argi] = strtoul(value, NULL, 16);
525 argi++;
526 if (argi >= BINARY_MAX_ARGS) {
527 fprintf(stderr,
528 "Too many argument for binary\n");
529 return -1;
530 }
531 }
532 el->binary.nargs = argi;
533 } else if (!strcmp(keyword, "DATA")) {
534 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
535 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
536
537 if (!value1 || !value2) {
538 fprintf(stderr,
539 "Invalid number of arguments for DATA\n");
540 return -1;
541 }
542
543 el->type = IMAGE_CFG_DATA;
544 el->regdata.raddr = strtoul(value1, NULL, 16);
545 el->regdata.rdata = strtoul(value2, NULL, 16);
546 } else {
547 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
548 }
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530549
550 return 0;
551}
552
Stefan Roese4acd2d22014-10-22 12:13:23 +0200553/*
554 * Parse the configuration file 'fcfg' into the array of configuration
555 * elements 'image_cfg', and return the number of configuration
556 * elements in 'cfgn'.
557 */
558static int image_create_config_parse(FILE *fcfg)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530559{
Stefan Roese4acd2d22014-10-22 12:13:23 +0200560 int ret;
561 int cfgi = 0;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530562
Stefan Roese4acd2d22014-10-22 12:13:23 +0200563 /* Parse the configuration file */
564 while (!feof(fcfg)) {
565 char *line;
566 char buf[256];
567
568 /* Read the current line */
569 memset(buf, 0, sizeof(buf));
570 line = fgets(buf, sizeof(buf), fcfg);
571 if (!line)
572 break;
573
574 /* Ignore useless lines */
575 if (line[0] == '\n' || line[0] == '#')
576 continue;
577
578 /* Strip final newline */
579 if (line[strlen(line) - 1] == '\n')
580 line[strlen(line) - 1] = 0;
581
582 /* Parse the current line */
583 ret = image_create_config_parse_oneline(line,
584 &image_cfg[cfgi]);
585 if (ret)
586 return ret;
587
588 cfgi++;
589
590 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
591 fprintf(stderr,
592 "Too many configuration elements in .cfg file\n");
593 return -1;
594 }
595 }
596
597 cfgn = cfgi;
598 return 0;
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530599}
600
Stefan Roese4acd2d22014-10-22 12:13:23 +0200601static int image_get_version(void)
602{
603 struct image_cfg_element *e;
604
605 e = image_find_option(IMAGE_CFG_VERSION);
606 if (!e)
607 return -1;
608
609 return e->version;
610}
611
612static int image_version_file(const char *input)
613{
614 FILE *fcfg;
615 int version;
616 int ret;
617
618 fcfg = fopen(input, "r");
619 if (!fcfg) {
620 fprintf(stderr, "Could not open input file %s\n", input);
621 return -1;
622 }
623
624 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
625 sizeof(struct image_cfg_element));
626 if (!image_cfg) {
627 fprintf(stderr, "Cannot allocate memory\n");
628 fclose(fcfg);
629 return -1;
630 }
631
632 memset(image_cfg, 0,
633 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
634 rewind(fcfg);
635
636 ret = image_create_config_parse(fcfg);
637 fclose(fcfg);
638 if (ret) {
639 free(image_cfg);
640 return -1;
641 }
642
643 version = image_get_version();
644 /* Fallback to version 0 is no version is provided in the cfg file */
645 if (version == -1)
646 version = 0;
647
648 free(image_cfg);
649
650 return version;
651}
652
653static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
654 struct image_tool_params *params)
655{
656 FILE *fcfg;
657 void *image = NULL;
658 int version;
Łukasz Majewski93e93712014-11-21 09:22:43 +0100659 size_t headersz = 0;
Stefan Roese4acd2d22014-10-22 12:13:23 +0200660 uint32_t checksum;
661 int ret;
662 int size;
663
664 fcfg = fopen(params->imagename, "r");
665 if (!fcfg) {
666 fprintf(stderr, "Could not open input file %s\n",
667 params->imagename);
668 exit(EXIT_FAILURE);
669 }
670
671 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
672 sizeof(struct image_cfg_element));
673 if (!image_cfg) {
674 fprintf(stderr, "Cannot allocate memory\n");
675 fclose(fcfg);
676 exit(EXIT_FAILURE);
677 }
678
679 memset(image_cfg, 0,
680 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
681 rewind(fcfg);
682
683 ret = image_create_config_parse(fcfg);
684 fclose(fcfg);
685 if (ret) {
686 free(image_cfg);
687 exit(EXIT_FAILURE);
688 }
689
Stefan Roese9b163d82015-09-01 13:46:35 +0200690 /* The MVEBU BootROM does not allow non word aligned payloads */
691 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
692
Stefan Roese4acd2d22014-10-22 12:13:23 +0200693 version = image_get_version();
Stefan Roese934a5292014-10-28 11:32:24 +0100694 switch (version) {
695 /*
696 * Fallback to version 0 if no version is provided in the
697 * cfg file
698 */
699 case -1:
700 case 0:
Stefan Roese4acd2d22014-10-22 12:13:23 +0200701 image = image_create_v0(&headersz, params, sbuf->st_size);
Stefan Roese934a5292014-10-28 11:32:24 +0100702 break;
703
704 case 1:
Stefan Roese4acd2d22014-10-22 12:13:23 +0200705 image = image_create_v1(&headersz, params, sbuf->st_size);
Stefan Roese934a5292014-10-28 11:32:24 +0100706 break;
707
708 default:
709 fprintf(stderr, "Unsupported version %d\n", version);
710 free(image_cfg);
711 exit(EXIT_FAILURE);
712 }
Stefan Roese4acd2d22014-10-22 12:13:23 +0200713
714 if (!image) {
715 fprintf(stderr, "Could not create image\n");
716 free(image_cfg);
717 exit(EXIT_FAILURE);
718 }
719
720 free(image_cfg);
721
722 /* Build and add image checksum header */
723 checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
724 size = write(ifd, &checksum, sizeof(uint32_t));
725 if (size != sizeof(uint32_t)) {
726 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
727 params->cmdname, size, params->imagefile);
728 exit(EXIT_FAILURE);
729 }
730
731 sbuf->st_size += sizeof(uint32_t);
732
733 /* Finally copy the header into the image area */
734 memcpy(ptr, image, headersz);
735
736 free(image);
737}
738
739static void kwbimage_print_header(const void *ptr)
740{
741 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
742
743 printf("Image Type: MVEBU Boot from %s Image\n",
744 image_boot_mode_name(mhdr->blockid));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200745 printf("Image version:%d\n", image_version((void *)ptr));
Gerald Kerma26f195c2014-10-31 01:03:27 +0100746 printf("Data Size: ");
Stefan Roese4acd2d22014-10-22 12:13:23 +0200747 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
748 printf("Load Address: %08x\n", mhdr->destaddr);
749 printf("Entry Point: %08x\n", mhdr->execaddr);
750}
751
752static int kwbimage_check_image_types(uint8_t type)
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530753{
754 if (type == IH_TYPE_KWBIMAGE)
755 return EXIT_SUCCESS;
756 else
757 return EXIT_FAILURE;
758}
759
Stefan Roese4acd2d22014-10-22 12:13:23 +0200760static int kwbimage_verify_header(unsigned char *ptr, int image_size,
761 struct image_tool_params *params)
762{
763 struct main_hdr_v0 *main_hdr;
764 struct ext_hdr_v0 *ext_hdr;
765 uint8_t checksum;
766
767 main_hdr = (void *)ptr;
768 checksum = image_checksum8(ptr,
Gerald Kerma26f195c2014-10-31 01:03:27 +0100769 sizeof(struct main_hdr_v0)
770 - sizeof(uint8_t));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200771 if (checksum != main_hdr->checksum)
772 return -FDT_ERR_BADSTRUCTURE;
773
774 /* Only version 0 extended header has checksum */
775 if (image_version((void *)ptr) == 0) {
776 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
777 checksum = image_checksum8(ext_hdr,
Gerald Kerma26f195c2014-10-31 01:03:27 +0100778 sizeof(struct ext_hdr_v0)
779 - sizeof(uint8_t));
Stefan Roese4acd2d22014-10-22 12:13:23 +0200780 if (checksum != ext_hdr->checksum)
781 return -FDT_ERR_BADSTRUCTURE;
782 }
783
784 return 0;
785}
786
787static int kwbimage_generate(struct image_tool_params *params,
788 struct image_type_params *tparams)
789{
790 int alloc_len;
791 void *hdr;
792 int version = 0;
793
794 version = image_version_file(params->imagename);
795 if (version == 0) {
796 alloc_len = sizeof(struct main_hdr_v0) +
797 sizeof(struct ext_hdr_v0);
798 } else {
799 alloc_len = image_headersz_v1(params, NULL);
800 }
801
802 hdr = malloc(alloc_len);
803 if (!hdr) {
804 fprintf(stderr, "%s: malloc return failure: %s\n",
805 params->cmdname, strerror(errno));
806 exit(EXIT_FAILURE);
807 }
808
809 memset(hdr, 0, alloc_len);
810 tparams->header_size = alloc_len;
811 tparams->hdr = hdr;
812
813 return 0;
814}
815
816/*
817 * Report Error if xflag is set in addition to default
818 */
819static int kwbimage_check_params(struct image_tool_params *params)
820{
821 if (!strlen(params->imagename)) {
822 fprintf(stderr, "Error:%s - Configuration file not specified, "
823 "it is needed for kwbimage generation\n",
824 params->cmdname);
825 return CFG_INVALID;
826 }
827
828 return (params->dflag && (params->fflag || params->lflag)) ||
829 (params->fflag && (params->dflag || params->lflag)) ||
830 (params->lflag && (params->dflag || params->fflag)) ||
831 (params->xflag) || !(strlen(params->imagename));
832}
833
Prafulla Wadaskaraa0c7a82009-09-07 15:05:02 +0530834/*
835 * kwbimage type parameters definition
836 */
Guilherme Maciel Ferreiraa93648d2015-01-15 02:48:07 -0200837U_BOOT_IMAGE_TYPE(
838 kwbimage,
839 "Marvell MVEBU Boot Image support",
840 0,
841 NULL,
842 kwbimage_check_params,
843 kwbimage_verify_header,
844 kwbimage_print_header,
845 kwbimage_set_header,
846 NULL,
847 kwbimage_check_image_types,
848 NULL,
849 kwbimage_generate
850);