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