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