Merge branch 'master' of git://git.denx.de/u-boot-spi
[oweals/u-boot.git] / 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         } 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
92
93 /*
94  * Utility functions to manipulate boot mode and ecc modes (convert
95  * them back and forth between description strings and the
96  * corresponding numerical identifiers).
97  */
98
99 static const char *image_boot_mode_name(unsigned int id)
100 {
101         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
108 int 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
118 int 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
127 static struct image_cfg_element *
128 image_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
140 static unsigned int
141 image_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  */
157 static uint8_t image_checksum8(void *start, uint32_t len)
158 {
159         uint8_t csum = 0;
160         uint8_t *p = start;
161
162         /* check len and return zero checksum if invalid */
163         if (!len)
164                 return 0;
165
166         do {
167                 csum += *p;
168                 p++;
169         } while (--len);
170
171         return csum;
172 }
173
174 static uint32_t image_checksum32(void *start, uint32_t len)
175 {
176         uint32_t csum = 0;
177         uint32_t *p = start;
178
179         /* check len and return zero checksum if invalid */
180         if (!len)
181                 return 0;
182
183         if (len % sizeof(uint32_t)) {
184                 fprintf(stderr, "Length %d is not in multiple of %zu\n",
185                         len, sizeof(uint32_t));
186                 return 0;
187         }
188
189         do {
190                 csum += *p;
191                 p++;
192                 len -= sizeof(uint32_t);
193         } while (len > 0);
194
195         return csum;
196 }
197
198 static void *image_create_v0(size_t *imagesz, struct image_tool_params *params,
199                              int payloadsz)
200 {
201         struct image_cfg_element *e;
202         size_t headersz;
203         struct main_hdr_v0 *main_hdr;
204         struct ext_hdr_v0 *ext_hdr;
205         void *image;
206         int has_ext = 0;
207
208         /*
209          * Calculate the size of the header and the size of the
210          * payload
211          */
212         headersz  = sizeof(struct main_hdr_v0);
213
214         if (image_count_options(IMAGE_CFG_DATA) > 0) {
215                 has_ext = 1;
216                 headersz += sizeof(struct ext_hdr_v0);
217         }
218
219         if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
220                 fprintf(stderr, "More than one payload, not possible\n");
221                 return NULL;
222         }
223
224         image = malloc(headersz);
225         if (!image) {
226                 fprintf(stderr, "Cannot allocate memory for image\n");
227                 return NULL;
228         }
229
230         memset(image, 0, headersz);
231
232         main_hdr = image;
233
234         /* Fill in the main header */
235         main_hdr->blocksize = payloadsz + sizeof(uint32_t) - headersz;
236         main_hdr->srcaddr   = headersz;
237         main_hdr->ext       = has_ext;
238         main_hdr->destaddr  = params->addr;
239         main_hdr->execaddr  = params->ep;
240
241         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));
252
253         /* Generate the ext header */
254         if (has_ext) {
255                 int cfgi, datai;
256
257                 ext_hdr = image + sizeof(struct main_hdr_v0);
258                 ext_hdr->offset = 0x40;
259
260                 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++;
268                 }
269
270                 ext_hdr->checksum = image_checksum8(ext_hdr,
271                                                     sizeof(struct ext_hdr_v0));
272         }
273
274         *imagesz = headersz;
275         return image;
276 }
277
278 static size_t image_headersz_v1(struct image_tool_params *params,
279                                 int *hasext)
280 {
281         struct image_cfg_element *binarye;
282         size_t headersz;
283         int ret;
284
285         /*
286          * Calculate the size of the header and the size of the
287          * payload
288          */
289         headersz = sizeof(struct main_hdr_v1);
290
291         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) {
307                         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
316                         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",
320                                 binarye->binary.file, dir);
321                         return 0;
322                 }
323
324                 headersz += s.st_size +
325                         binarye->binary.nargs * sizeof(unsigned int);
326                 if (hasext)
327                         *hasext = 1;
328         }
329
330 #if defined(CONFIG_SYS_U_BOOT_OFFS)
331         if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
332                 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
333                 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");
336                 return 0;
337         } else {
338                 headersz = CONFIG_SYS_U_BOOT_OFFS;
339         }
340 #endif
341
342         /*
343          * The payload should be aligned on some reasonable
344          * boundary
345          */
346         return ALIGN_SUP(headersz, 4096);
347 }
348
349 static 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;
420
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;
427                 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
450                 cur += ALIGN_SUP(s.st_size, 4);
451
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                  */
458                 *((uint32_t *)cur) = 0x00000000;
459
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
470 static 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);
483                 int ret = image_boot_mode_id(value);
484                 if (ret < 0) {
485                         fprintf(stderr,
486                                 "Invalid boot media '%s'\n", value);
487                         return -1;
488                 }
489                 el->type = IMAGE_CFG_BOOT_FROM;
490                 el->bootfrom = ret;
491         } 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);
502                 int ret = image_nand_ecc_mode_id(value);
503                 if (ret < 0) {
504                         fprintf(stderr,
505                                 "Invalid NAND ECC mode '%s'\n", value);
506                         return -1;
507                 }
508                 el->type = IMAGE_CFG_NAND_ECC_MODE;
509                 el->nandeccmode = ret;
510         } 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         }
549
550         return 0;
551 }
552
553 /*
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  */
558 static int image_create_config_parse(FILE *fcfg)
559 {
560         int ret;
561         int cfgi = 0;
562
563         /* 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;
599 }
600
601 static 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
612 static 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
653 static 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;
659         size_t headersz = 0;
660         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
690         /* The MVEBU BootROM does not allow non word aligned payloads */
691         sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
692
693         version = image_get_version();
694         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:
701                 image = image_create_v0(&headersz, params, sbuf->st_size);
702                 break;
703
704         case 1:
705                 image = image_create_v1(&headersz, params, sbuf->st_size);
706                 break;
707
708         default:
709                 fprintf(stderr, "Unsupported version %d\n", version);
710                 free(image_cfg);
711                 exit(EXIT_FAILURE);
712         }
713
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
739 static 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));
745         printf("Image version:%d\n", image_version((void *)ptr));
746         printf("Data Size:    ");
747         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
752 static int kwbimage_check_image_types(uint8_t type)
753 {
754         if (type == IH_TYPE_KWBIMAGE)
755                 return EXIT_SUCCESS;
756         else
757                 return EXIT_FAILURE;
758 }
759
760 static 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,
769                                    sizeof(struct main_hdr_v0)
770                                    - sizeof(uint8_t));
771         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,
778                                            sizeof(struct ext_hdr_v0)
779                                            - sizeof(uint8_t));
780                 if (checksum != ext_hdr->checksum)
781                         return -FDT_ERR_BADSTRUCTURE;
782         }
783
784         return 0;
785 }
786
787 static 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  */
819 static 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
834 /*
835  * kwbimage type parameters definition
836  */
837 U_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 );