]> git.ipfire.org Git - people/ms/u-boot.git/blame - tools/kwbimage.c
tools: kwbimage: Factor out add_binary_header_v1
[people/ms/u-boot.git] / tools / kwbimage.c
CommitLineData
aa0c7a86 1/*
4acd2d24
SR
2 * 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>
aa0c7a86 7 *
1a459660 8 * SPDX-License-Identifier: GPL-2.0+
4acd2d24
SR
9 *
10 * Not implemented: support for the register headers and secure
11 * headers in v1 images
aa0c7a86
PW
12 */
13
f86ed6a8 14#include "imagetool.h"
e5f1a586 15#include <limits.h>
aa0c7a86 16#include <image.h>
4acd2d24 17#include <stdint.h>
aa0c7a86
PW
18#include "kwbimage.h"
19
4acd2d24
SR
20static 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" },
1bbe63c3 35 { 0xAE, "sdio" },
4acd2d24 36 {},
aa0c7a86
PW
37};
38
4acd2d24
SR
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,
4bdb5479 71 IMAGE_CFG_BAUDRATE,
2611c05e 72 IMAGE_CFG_DEBUG,
4acd2d24
SR
73 } 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;
4bdb5479 90 unsigned int baudrate;
2611c05e 91 unsigned int debug;
4acd2d24
SR
92 };
93};
94
95#define IMAGE_CFG_ELEMENT_MAX 256
aa0c7a86 96
4acd2d24
SR
97/*
98 * 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)
104{
105 int i;
94490a4a 106
4acd2d24
SR
107 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}
112
113int image_boot_mode_id(const char *boot_mode_name)
114{
115 int i;
94490a4a 116
4acd2d24
SR
117 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;
94490a4a 127
4acd2d24
SR
128 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;
aa0c7a86
PW
132}
133
4acd2d24
SR
134static struct image_cfg_element *
135image_find_option(unsigned int optiontype)
aa0c7a86 136{
4acd2d24 137 int i;
aa0c7a86 138
4acd2d24
SR
139 for (i = 0; i < cfgn; i++) {
140 if (image_cfg[i].type == optiontype)
141 return &image_cfg[i];
aa0c7a86 142 }
4acd2d24
SR
143
144 return NULL;
145}
146
147static 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;
aa0c7a86
PW
158}
159
160/*
4acd2d24
SR
161 * Compute a 8-bit checksum of a memory area. This algorithm follows
162 * the requirements of the Marvell SoC BootROM specifications.
aa0c7a86 163 */
4acd2d24 164static uint8_t image_checksum8(void *start, uint32_t len)
aa0c7a86 165{
4acd2d24
SR
166 uint8_t csum = 0;
167 uint8_t *p = start;
aa0c7a86
PW
168
169 /* check len and return zero checksum if invalid */
170 if (!len)
171 return 0;
172
173 do {
4acd2d24 174 csum += *p;
aa0c7a86
PW
175 p++;
176 } while (--len);
4acd2d24
SR
177
178 return csum;
aa0c7a86
PW
179}
180
4acd2d24 181static uint32_t image_checksum32(void *start, uint32_t len)
aa0c7a86 182{
4acd2d24
SR
183 uint32_t csum = 0;
184 uint32_t *p = start;
aa0c7a86
PW
185
186 /* check len and return zero checksum if invalid */
187 if (!len)
188 return 0;
189
190 if (len % sizeof(uint32_t)) {
4acd2d24
SR
191 fprintf(stderr, "Length %d is not in multiple of %zu\n",
192 len, sizeof(uint32_t));
aa0c7a86
PW
193 return 0;
194 }
195
196 do {
4acd2d24 197 csum += *p;
aa0c7a86
PW
198 p++;
199 len -= sizeof(uint32_t);
200 } while (len > 0);
4acd2d24
SR
201
202 return csum;
aa0c7a86
PW
203}
204
4bdb5479
CP
205static 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
4acd2d24
SR
227static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
228 int payloadsz)
aa0c7a86 229{
4acd2d24
SR
230 struct image_cfg_element *e;
231 size_t headersz;
232 struct main_hdr_v0 *main_hdr;
885fba15 233 uint8_t *image;
4acd2d24
SR
234 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 }
aa0c7a86 251
4acd2d24
SR
252 image = malloc(headersz);
253 if (!image) {
254 fprintf(stderr, "Cannot allocate memory for image\n");
255 return NULL;
aa0c7a86 256 }
aa0c7a86 257
4acd2d24
SR
258 memset(image, 0, headersz);
259
885fba15 260 main_hdr = (struct main_hdr_v0 *)image;
4acd2d24
SR
261
262 /* Fill in the main header */
a8840dce
RP
263 main_hdr->blocksize =
264 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
265 main_hdr->srcaddr = cpu_to_le32(headersz);
4acd2d24 266 main_hdr->ext = has_ext;
a8840dce
RP
267 main_hdr->destaddr = cpu_to_le32(params->addr);
268 main_hdr->execaddr = cpu_to_le32(params->ep);
4acd2d24
SR
269
270 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)
a8840dce 278 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
4acd2d24
SR
279 main_hdr->checksum = image_checksum8(image,
280 sizeof(struct main_hdr_v0));
281
282 /* Generate the ext header */
283 if (has_ext) {
e89016c4 284 struct ext_hdr_v0 *ext_hdr;
4acd2d24
SR
285 int cfgi, datai;
286
885fba15
MS
287 ext_hdr = (struct ext_hdr_v0 *)
288 (image + sizeof(struct main_hdr_v0));
a8840dce 289 ext_hdr->offset = cpu_to_le32(0x40);
4acd2d24
SR
290
291 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
292 e = &image_cfg[cfgi];
293 if (e->type != IMAGE_CFG_DATA)
294 continue;
295
a8840dce
RP
296 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);
4acd2d24
SR
300 datai++;
301 }
302
303 ext_hdr->checksum = image_checksum8(ext_hdr,
304 sizeof(struct ext_hdr_v0));
305 }
306
307 *imagesz = headersz;
308 return image;
aa0c7a86
PW
309}
310
e93cf53f 311static size_t image_headersz_v1(int *hasext)
4acd2d24
SR
312{
313 struct image_cfg_element *binarye;
314 size_t headersz;
4acd2d24
SR
315
316 /*
317 * Calculate the size of the header and the size of the
318 * payload
319 */
320 headersz = sizeof(struct main_hdr_v1);
321
322 if (image_count_options(IMAGE_CFG_BINARY) > 1) {
323 fprintf(stderr, "More than one binary blob, not supported\n");
324 return 0;
aa0c7a86
PW
325 }
326
4acd2d24
SR
327 if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
328 fprintf(stderr, "More than one payload, not possible\n");
329 return 0;
330 }
aa0c7a86 331
4acd2d24
SR
332 binarye = image_find_option(IMAGE_CFG_BINARY);
333 if (binarye) {
e89016c4 334 int ret;
4acd2d24
SR
335 struct stat s;
336
337 ret = stat(binarye->binary.file, &s);
338 if (ret < 0) {
e5f1a586
AB
339 char cwd[PATH_MAX];
340 char *dir = cwd;
341
342 memset(cwd, 0, sizeof(cwd));
343 if (!getcwd(cwd, sizeof(cwd))) {
344 dir = "current working directory";
345 perror("getcwd() failed");
346 }
347
4acd2d24
SR
348 fprintf(stderr,
349 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
350 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
351 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
e5f1a586 352 binarye->binary.file, dir);
4acd2d24
SR
353 return 0;
354 }
aa0c7a86 355
76b391cd
RP
356 headersz += sizeof(struct opt_hdr_v1) +
357 s.st_size +
358 (binarye->binary.nargs + 2) * sizeof(uint32_t);
4acd2d24
SR
359 if (hasext)
360 *hasext = 1;
361 }
aa0c7a86 362
7ddf8cfb
SR
363#if defined(CONFIG_SYS_U_BOOT_OFFS)
364 if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
94490a4a
MS
365 fprintf(stderr,
366 "Error: Image header (incl. SPL image) too big!\n");
7ddf8cfb
SR
367 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
368 (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
369 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
a0aad123 370 return 0;
a0aad123 371 }
79066ef8 372
94490a4a 373 headersz = CONFIG_SYS_U_BOOT_OFFS;
a0aad123
KS
374#endif
375
4acd2d24
SR
376 /*
377 * The payload should be aligned on some reasonable
378 * boundary
379 */
380 return ALIGN_SUP(headersz, 4096);
381}
aa0c7a86 382
79066ef8
MS
383int add_binary_header_v1(uint8_t *cur)
384{
385 struct image_cfg_element *binarye;
386 struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur;
387 uint32_t *args;
388 size_t binhdrsz;
389 struct stat s;
390 int argi;
391 FILE *bin;
392 int ret;
393
394 binarye = image_find_option(IMAGE_CFG_BINARY);
395
396 if (!binarye)
397 return 0;
398
399 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
400
401 bin = fopen(binarye->binary.file, "r");
402 if (!bin) {
403 fprintf(stderr, "Cannot open binary file %s\n",
404 binarye->binary.file);
405 return -1;
406 }
407
408 fstat(fileno(bin), &s);
409
410 binhdrsz = sizeof(struct opt_hdr_v1) +
411 (binarye->binary.nargs + 2) * sizeof(uint32_t) +
412 s.st_size;
413
414 /*
415 * The size includes the binary image size, rounded
416 * up to a 4-byte boundary. Plus 4 bytes for the
417 * next-header byte and 3-byte alignment at the end.
418 */
419 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
420 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
421 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
422
423 cur += sizeof(struct opt_hdr_v1);
424
425 args = (uint32_t *)cur;
426 *args = cpu_to_le32(binarye->binary.nargs);
427 args++;
428 for (argi = 0; argi < binarye->binary.nargs; argi++)
429 args[argi] = cpu_to_le32(binarye->binary.args[argi]);
430
431 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
432
433 ret = fread(cur, s.st_size, 1, bin);
434 if (ret != 1) {
435 fprintf(stderr,
436 "Could not read binary image %s\n",
437 binarye->binary.file);
438 return -1;
439 }
440
441 fclose(bin);
442
443 cur += ALIGN_SUP(s.st_size, 4);
444
445 /*
446 * For now, we don't support more than one binary
447 * header, and no other header types are
448 * supported. So, the binary header is necessarily the
449 * last one
450 */
451 *((uint32_t *)cur) = 0x00000000;
452
453 cur += sizeof(uint32_t);
454
455 return 0;
456}
457
4acd2d24
SR
458static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
459 int payloadsz)
460{
79066ef8 461 struct image_cfg_element *e;
4acd2d24
SR
462 struct main_hdr_v1 *main_hdr;
463 size_t headersz;
885fba15 464 uint8_t *image, *cur;
4acd2d24 465 int hasext = 0;
4acd2d24
SR
466
467 /*
468 * Calculate the size of the header and the size of the
469 * payload
470 */
e93cf53f 471 headersz = image_headersz_v1(&hasext);
4acd2d24
SR
472 if (headersz == 0)
473 return NULL;
474
475 image = malloc(headersz);
476 if (!image) {
477 fprintf(stderr, "Cannot allocate memory for image\n");
478 return NULL;
479 }
aa0c7a86 480
4acd2d24
SR
481 memset(image, 0, headersz);
482
885fba15
MS
483 main_hdr = (struct main_hdr_v1 *)image;
484 cur = image + sizeof(struct main_hdr_v1);
4acd2d24
SR
485
486 /* Fill the main header */
a8840dce
RP
487 main_hdr->blocksize =
488 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
489 main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
4acd2d24 490 main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
94084eea
MS
491 main_hdr->destaddr = cpu_to_le32(params->addr)
492 - sizeof(image_header_t);
a8840dce
RP
493 main_hdr->execaddr = cpu_to_le32(params->ep);
494 main_hdr->srcaddr = cpu_to_le32(headersz);
4acd2d24
SR
495 main_hdr->ext = hasext;
496 main_hdr->version = 1;
497 e = image_find_option(IMAGE_CFG_BOOT_FROM);
498 if (e)
499 main_hdr->blockid = e->bootfrom;
500 e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
501 if (e)
502 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
503 e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
504 if (e)
505 main_hdr->nandbadblklocation = e->nandbadblklocation;
4bdb5479
CP
506 e = image_find_option(IMAGE_CFG_BAUDRATE);
507 if (e)
508 main_hdr->options = baudrate_to_option(e->baudrate);
2611c05e
CP
509 e = image_find_option(IMAGE_CFG_DEBUG);
510 if (e)
511 main_hdr->flags = e->debug ? 0x1 : 0;
4acd2d24 512
79066ef8
MS
513 if (add_binary_header_v1(cur))
514 return NULL;
4acd2d24
SR
515
516 /* Calculate and set the header checksum */
517 main_hdr->checksum = image_checksum8(main_hdr, headersz);
518
519 *imagesz = headersz;
520 return image;
521}
522
523static int image_create_config_parse_oneline(char *line,
524 struct image_cfg_element *el)
525{
526 char *keyword, *saveptr;
527 char deliminiters[] = " \t";
528
529 keyword = strtok_r(line, deliminiters, &saveptr);
530 if (!strcmp(keyword, "VERSION")) {
531 char *value = strtok_r(NULL, deliminiters, &saveptr);
94490a4a 532
4acd2d24
SR
533 el->type = IMAGE_CFG_VERSION;
534 el->version = atoi(value);
535 } else if (!strcmp(keyword, "BOOT_FROM")) {
536 char *value = strtok_r(NULL, deliminiters, &saveptr);
f411b8f2 537 int ret = image_boot_mode_id(value);
94490a4a 538
f411b8f2 539 if (ret < 0) {
4acd2d24
SR
540 fprintf(stderr,
541 "Invalid boot media '%s'\n", value);
542 return -1;
543 }
f411b8f2
AB
544 el->type = IMAGE_CFG_BOOT_FROM;
545 el->bootfrom = ret;
4acd2d24
SR
546 } else if (!strcmp(keyword, "NAND_BLKSZ")) {
547 char *value = strtok_r(NULL, deliminiters, &saveptr);
94490a4a 548
4acd2d24
SR
549 el->type = IMAGE_CFG_NAND_BLKSZ;
550 el->nandblksz = strtoul(value, NULL, 16);
551 } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
552 char *value = strtok_r(NULL, deliminiters, &saveptr);
94490a4a 553
4acd2d24
SR
554 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
555 el->nandbadblklocation =
556 strtoul(value, NULL, 16);
557 } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
558 char *value = strtok_r(NULL, deliminiters, &saveptr);
f411b8f2 559 int ret = image_nand_ecc_mode_id(value);
94490a4a 560
f411b8f2 561 if (ret < 0) {
4acd2d24
SR
562 fprintf(stderr,
563 "Invalid NAND ECC mode '%s'\n", value);
564 return -1;
565 }
f411b8f2
AB
566 el->type = IMAGE_CFG_NAND_ECC_MODE;
567 el->nandeccmode = ret;
4acd2d24
SR
568 } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
569 char *value = strtok_r(NULL, deliminiters, &saveptr);
94490a4a 570
4acd2d24
SR
571 el->type = IMAGE_CFG_NAND_PAGESZ;
572 el->nandpagesz = strtoul(value, NULL, 16);
573 } else if (!strcmp(keyword, "BINARY")) {
574 char *value = strtok_r(NULL, deliminiters, &saveptr);
575 int argi = 0;
576
577 el->type = IMAGE_CFG_BINARY;
578 el->binary.file = strdup(value);
579 while (1) {
580 value = strtok_r(NULL, deliminiters, &saveptr);
581 if (!value)
582 break;
583 el->binary.args[argi] = strtoul(value, NULL, 16);
584 argi++;
585 if (argi >= BINARY_MAX_ARGS) {
586 fprintf(stderr,
587 "Too many argument for binary\n");
588 return -1;
aa0c7a86 589 }
aa0c7a86 590 }
4acd2d24
SR
591 el->binary.nargs = argi;
592 } else if (!strcmp(keyword, "DATA")) {
593 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
594 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
595
596 if (!value1 || !value2) {
597 fprintf(stderr,
598 "Invalid number of arguments for DATA\n");
599 return -1;
600 }
601
602 el->type = IMAGE_CFG_DATA;
603 el->regdata.raddr = strtoul(value1, NULL, 16);
604 el->regdata.rdata = strtoul(value2, NULL, 16);
4bdb5479
CP
605 } else if (!strcmp(keyword, "BAUDRATE")) {
606 char *value = strtok_r(NULL, deliminiters, &saveptr);
607 el->type = IMAGE_CFG_BAUDRATE;
608 el->baudrate = strtoul(value, NULL, 10);
2611c05e
CP
609 } else if (!strcmp(keyword, "DEBUG")) {
610 char *value = strtok_r(NULL, deliminiters, &saveptr);
611 el->type = IMAGE_CFG_DEBUG;
612 el->debug = strtoul(value, NULL, 10);
4acd2d24
SR
613 } else {
614 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
aa0c7a86 615 }
aa0c7a86 616
4acd2d24
SR
617 return 0;
618}
aa0c7a86
PW
619
620/*
4acd2d24
SR
621 * Parse the configuration file 'fcfg' into the array of configuration
622 * elements 'image_cfg', and return the number of configuration
623 * elements in 'cfgn'.
aa0c7a86 624 */
4acd2d24
SR
625static int image_create_config_parse(FILE *fcfg)
626{
627 int ret;
628 int cfgi = 0;
629
630 /* Parse the configuration file */
631 while (!feof(fcfg)) {
632 char *line;
633 char buf[256];
634
635 /* Read the current line */
636 memset(buf, 0, sizeof(buf));
637 line = fgets(buf, sizeof(buf), fcfg);
638 if (!line)
639 break;
640
641 /* Ignore useless lines */
642 if (line[0] == '\n' || line[0] == '#')
643 continue;
644
645 /* Strip final newline */
646 if (line[strlen(line) - 1] == '\n')
647 line[strlen(line) - 1] = 0;
648
649 /* Parse the current line */
650 ret = image_create_config_parse_oneline(line,
651 &image_cfg[cfgi]);
652 if (ret)
653 return ret;
654
655 cfgi++;
656
657 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
658 fprintf(stderr,
659 "Too many configuration elements in .cfg file\n");
660 return -1;
661 }
662 }
663
664 cfgn = cfgi;
665 return 0;
666}
667
668static int image_get_version(void)
669{
670 struct image_cfg_element *e;
671
672 e = image_find_option(IMAGE_CFG_VERSION);
673 if (!e)
674 return -1;
675
676 return e->version;
677}
678
679static int image_version_file(const char *input)
680{
681 FILE *fcfg;
682 int version;
683 int ret;
684
685 fcfg = fopen(input, "r");
686 if (!fcfg) {
687 fprintf(stderr, "Could not open input file %s\n", input);
688 return -1;
689 }
690
691 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
692 sizeof(struct image_cfg_element));
693 if (!image_cfg) {
694 fprintf(stderr, "Cannot allocate memory\n");
695 fclose(fcfg);
696 return -1;
697 }
698
699 memset(image_cfg, 0,
700 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
701 rewind(fcfg);
702
703 ret = image_create_config_parse(fcfg);
704 fclose(fcfg);
705 if (ret) {
706 free(image_cfg);
707 return -1;
708 }
709
710 version = image_get_version();
711 /* Fallback to version 0 is no version is provided in the cfg file */
712 if (version == -1)
713 version = 0;
714
715 free(image_cfg);
716
717 return version;
aa0c7a86
PW
718}
719
4acd2d24 720static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
f86ed6a8 721 struct image_tool_params *params)
aa0c7a86 722{
4acd2d24
SR
723 FILE *fcfg;
724 void *image = NULL;
725 int version;
93e9371f 726 size_t headersz = 0;
aa0c7a86 727 uint32_t checksum;
4acd2d24 728 int ret;
aa0c7a86
PW
729 int size;
730
4acd2d24
SR
731 fcfg = fopen(params->imagename, "r");
732 if (!fcfg) {
733 fprintf(stderr, "Could not open input file %s\n",
734 params->imagename);
735 exit(EXIT_FAILURE);
736 }
737
738 image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
739 sizeof(struct image_cfg_element));
740 if (!image_cfg) {
741 fprintf(stderr, "Cannot allocate memory\n");
742 fclose(fcfg);
743 exit(EXIT_FAILURE);
744 }
745
746 memset(image_cfg, 0,
747 IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
748 rewind(fcfg);
749
750 ret = image_create_config_parse(fcfg);
751 fclose(fcfg);
752 if (ret) {
753 free(image_cfg);
754 exit(EXIT_FAILURE);
755 }
756
9b163d8c
SR
757 /* The MVEBU BootROM does not allow non word aligned payloads */
758 sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
759
4acd2d24 760 version = image_get_version();
934a529f
SR
761 switch (version) {
762 /*
763 * Fallback to version 0 if no version is provided in the
764 * cfg file
765 */
766 case -1:
767 case 0:
4acd2d24 768 image = image_create_v0(&headersz, params, sbuf->st_size);
934a529f
SR
769 break;
770
771 case 1:
4acd2d24 772 image = image_create_v1(&headersz, params, sbuf->st_size);
934a529f
SR
773 break;
774
775 default:
776 fprintf(stderr, "Unsupported version %d\n", version);
777 free(image_cfg);
778 exit(EXIT_FAILURE);
779 }
4acd2d24
SR
780
781 if (!image) {
782 fprintf(stderr, "Could not create image\n");
783 free(image_cfg);
784 exit(EXIT_FAILURE);
785 }
786
787 free(image_cfg);
aa0c7a86 788
4acd2d24 789 /* Build and add image checksum header */
a8840dce
RP
790 checksum =
791 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
4acd2d24 792 size = write(ifd, &checksum, sizeof(uint32_t));
aa0c7a86 793 if (size != sizeof(uint32_t)) {
4acd2d24 794 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
aa0c7a86 795 params->cmdname, size, params->imagefile);
4acd2d24 796 exit(EXIT_FAILURE);
aa0c7a86
PW
797 }
798
799 sbuf->st_size += sizeof(uint32_t);
800
4acd2d24
SR
801 /* Finally copy the header into the image area */
802 memcpy(ptr, image, headersz);
aa0c7a86 803
4acd2d24 804 free(image);
aa0c7a86
PW
805}
806
4acd2d24 807static void kwbimage_print_header(const void *ptr)
aa0c7a86 808{
4acd2d24
SR
809 struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
810
811 printf("Image Type: MVEBU Boot from %s Image\n",
812 image_boot_mode_name(mhdr->blockid));
4acd2d24 813 printf("Image version:%d\n", image_version((void *)ptr));
26f195c7 814 printf("Data Size: ");
4acd2d24
SR
815 genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
816 printf("Load Address: %08x\n", mhdr->destaddr);
817 printf("Entry Point: %08x\n", mhdr->execaddr);
aa0c7a86
PW
818}
819
4acd2d24 820static int kwbimage_check_image_types(uint8_t type)
aa0c7a86
PW
821{
822 if (type == IH_TYPE_KWBIMAGE)
823 return EXIT_SUCCESS;
94490a4a
MS
824
825 return EXIT_FAILURE;
aa0c7a86
PW
826}
827
4acd2d24
SR
828static int kwbimage_verify_header(unsigned char *ptr, int image_size,
829 struct image_tool_params *params)
830{
831 struct main_hdr_v0 *main_hdr;
4acd2d24
SR
832 uint8_t checksum;
833
885fba15 834 main_hdr = (struct main_hdr_v0 *)ptr;
4acd2d24 835 checksum = image_checksum8(ptr,
26f195c7
GK
836 sizeof(struct main_hdr_v0)
837 - sizeof(uint8_t));
4acd2d24
SR
838 if (checksum != main_hdr->checksum)
839 return -FDT_ERR_BADSTRUCTURE;
840
841 /* Only version 0 extended header has checksum */
842 if (image_version((void *)ptr) == 0) {
e89016c4
MS
843 struct ext_hdr_v0 *ext_hdr;
844
885fba15
MS
845 ext_hdr = (struct ext_hdr_v0 *)
846 (ptr + sizeof(struct main_hdr_v0));
4acd2d24 847 checksum = image_checksum8(ext_hdr,
26f195c7
GK
848 sizeof(struct ext_hdr_v0)
849 - sizeof(uint8_t));
4acd2d24
SR
850 if (checksum != ext_hdr->checksum)
851 return -FDT_ERR_BADSTRUCTURE;
852 }
853
854 return 0;
855}
856
857static int kwbimage_generate(struct image_tool_params *params,
858 struct image_type_params *tparams)
859{
860 int alloc_len;
861 void *hdr;
862 int version = 0;
863
864 version = image_version_file(params->imagename);
865 if (version == 0) {
866 alloc_len = sizeof(struct main_hdr_v0) +
867 sizeof(struct ext_hdr_v0);
868 } else {
e93cf53f 869 alloc_len = image_headersz_v1(NULL);
4acd2d24
SR
870 }
871
872 hdr = malloc(alloc_len);
873 if (!hdr) {
874 fprintf(stderr, "%s: malloc return failure: %s\n",
875 params->cmdname, strerror(errno));
876 exit(EXIT_FAILURE);
877 }
878
879 memset(hdr, 0, alloc_len);
880 tparams->header_size = alloc_len;
881 tparams->hdr = hdr;
882
77720859
SR
883 /*
884 * The resulting image needs to be 4-byte aligned. At least
885 * the Marvell hdrparser tool complains if its unaligned.
886 * By returning 1 here in this function, called via
887 * tparams->vrec_header() in mkimage.c, mkimage will
888 * automatically pad the the resulting image to a 4-byte
889 * size if necessary.
890 */
891 return 1;
4acd2d24
SR
892}
893
894/*
895 * Report Error if xflag is set in addition to default
896 */
897static int kwbimage_check_params(struct image_tool_params *params)
898{
899 if (!strlen(params->imagename)) {
94490a4a
MS
900 char *msg = "Configuration file for kwbimage creation omitted";
901
902 fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg);
4acd2d24
SR
903 return CFG_INVALID;
904 }
905
906 return (params->dflag && (params->fflag || params->lflag)) ||
907 (params->fflag && (params->dflag || params->lflag)) ||
908 (params->lflag && (params->dflag || params->fflag)) ||
909 (params->xflag) || !(strlen(params->imagename));
910}
911
aa0c7a86
PW
912/*
913 * kwbimage type parameters definition
914 */
a93648d1
GMF
915U_BOOT_IMAGE_TYPE(
916 kwbimage,
917 "Marvell MVEBU Boot Image support",
918 0,
919 NULL,
920 kwbimage_check_params,
921 kwbimage_verify_header,
922 kwbimage_print_header,
923 kwbimage_set_header,
924 NULL,
925 kwbimage_check_image_types,
926 NULL,
927 kwbimage_generate
928);