Merge git://www.denx.de/git/u-boot-ppc4xx
[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 =
236                 cpu_to_le32(payloadsz + sizeof(uint32_t) - headersz);
237         main_hdr->srcaddr   = cpu_to_le32(headersz);
238         main_hdr->ext       = has_ext;
239         main_hdr->destaddr  = cpu_to_le32(params->addr);
240         main_hdr->execaddr  = cpu_to_le32(params->ep);
241
242         e = image_find_option(IMAGE_CFG_BOOT_FROM);
243         if (e)
244                 main_hdr->blockid = e->bootfrom;
245         e = image_find_option(IMAGE_CFG_NAND_ECC_MODE);
246         if (e)
247                 main_hdr->nandeccmode = e->nandeccmode;
248         e = image_find_option(IMAGE_CFG_NAND_PAGESZ);
249         if (e)
250                 main_hdr->nandpagesize = cpu_to_le16(e->nandpagesz);
251         main_hdr->checksum = image_checksum8(image,
252                                              sizeof(struct main_hdr_v0));
253
254         /* Generate the ext header */
255         if (has_ext) {
256                 int cfgi, datai;
257
258                 ext_hdr = image + sizeof(struct main_hdr_v0);
259                 ext_hdr->offset = cpu_to_le32(0x40);
260
261                 for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) {
262                         e = &image_cfg[cfgi];
263                         if (e->type != IMAGE_CFG_DATA)
264                                 continue;
265
266                         ext_hdr->rcfg[datai].raddr =
267                                 cpu_to_le32(e->regdata.raddr);
268                         ext_hdr->rcfg[datai].rdata =
269                                 cpu_to_le32(e->regdata.rdata);
270                         datai++;
271                 }
272
273                 ext_hdr->checksum = image_checksum8(ext_hdr,
274                                                     sizeof(struct ext_hdr_v0));
275         }
276
277         *imagesz = headersz;
278         return image;
279 }
280
281 static size_t image_headersz_v1(struct image_tool_params *params,
282                                 int *hasext)
283 {
284         struct image_cfg_element *binarye;
285         size_t headersz;
286         int ret;
287
288         /*
289          * Calculate the size of the header and the size of the
290          * payload
291          */
292         headersz = sizeof(struct main_hdr_v1);
293
294         if (image_count_options(IMAGE_CFG_BINARY) > 1) {
295                 fprintf(stderr, "More than one binary blob, not supported\n");
296                 return 0;
297         }
298
299         if (image_count_options(IMAGE_CFG_PAYLOAD) > 1) {
300                 fprintf(stderr, "More than one payload, not possible\n");
301                 return 0;
302         }
303
304         binarye = image_find_option(IMAGE_CFG_BINARY);
305         if (binarye) {
306                 struct stat s;
307
308                 ret = stat(binarye->binary.file, &s);
309                 if (ret < 0) {
310                         char cwd[PATH_MAX];
311                         char *dir = cwd;
312
313                         memset(cwd, 0, sizeof(cwd));
314                         if (!getcwd(cwd, sizeof(cwd))) {
315                                 dir = "current working directory";
316                                 perror("getcwd() failed");
317                         }
318
319                         fprintf(stderr,
320                                 "Didn't find the file '%s' in '%s' which is mandatory to generate the image\n"
321                                 "This file generally contains the DDR3 training code, and should be extracted from an existing bootable\n"
322                                 "image for your board. See 'kwbimage -x' to extract it from an existing image.\n",
323                                 binarye->binary.file, dir);
324                         return 0;
325                 }
326
327                 headersz += sizeof(struct opt_hdr_v1) +
328                         s.st_size +
329                         (binarye->binary.nargs + 2) * sizeof(uint32_t);
330                 if (hasext)
331                         *hasext = 1;
332         }
333
334 #if defined(CONFIG_SYS_U_BOOT_OFFS)
335         if (headersz > CONFIG_SYS_U_BOOT_OFFS) {
336                 fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
337                 fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n",
338                         (int)headersz, CONFIG_SYS_U_BOOT_OFFS);
339                 fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n");
340                 return 0;
341         } else {
342                 headersz = CONFIG_SYS_U_BOOT_OFFS;
343         }
344 #endif
345
346         /*
347          * The payload should be aligned on some reasonable
348          * boundary
349          */
350         return ALIGN_SUP(headersz, 4096);
351 }
352
353 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
354                              int payloadsz)
355 {
356         struct image_cfg_element *e, *binarye;
357         struct main_hdr_v1 *main_hdr;
358         size_t headersz;
359         void *image, *cur;
360         int hasext = 0;
361         int ret;
362
363         /*
364          * Calculate the size of the header and the size of the
365          * payload
366          */
367         headersz = image_headersz_v1(params, &hasext);
368         if (headersz == 0)
369                 return NULL;
370
371         image = malloc(headersz);
372         if (!image) {
373                 fprintf(stderr, "Cannot allocate memory for image\n");
374                 return NULL;
375         }
376
377         memset(image, 0, headersz);
378
379         cur = main_hdr = image;
380         cur += sizeof(struct main_hdr_v1);
381
382         /* Fill the main header */
383         main_hdr->blocksize    =
384                 cpu_to_le32(payloadsz - headersz + sizeof(uint32_t));
385         main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF);
386         main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
387         main_hdr->destaddr     = cpu_to_le32(params->addr);
388         main_hdr->execaddr     = cpu_to_le32(params->ep);
389         main_hdr->srcaddr      = cpu_to_le32(headersz);
390         main_hdr->ext          = hasext;
391         main_hdr->version      = 1;
392         e = image_find_option(IMAGE_CFG_BOOT_FROM);
393         if (e)
394                 main_hdr->blockid = e->bootfrom;
395         e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
396         if (e)
397                 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
398         e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
399         if (e)
400                 main_hdr->nandbadblklocation = e->nandbadblklocation;
401
402         binarye = image_find_option(IMAGE_CFG_BINARY);
403         if (binarye) {
404                 struct opt_hdr_v1 *hdr = cur;
405                 uint32_t *args;
406                 size_t binhdrsz;
407                 struct stat s;
408                 int argi;
409                 FILE *bin;
410
411                 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
412
413                 bin = fopen(binarye->binary.file, "r");
414                 if (!bin) {
415                         fprintf(stderr, "Cannot open binary file %s\n",
416                                 binarye->binary.file);
417                         return NULL;
418                 }
419
420                 fstat(fileno(bin), &s);
421
422                 binhdrsz = sizeof(struct opt_hdr_v1) +
423                         (binarye->binary.nargs + 2) * sizeof(uint32_t) +
424                         s.st_size;
425
426                 /*
427                  * The size includes the binary image size, rounded
428                  * up to a 4-byte boundary. Plus 4 bytes for the
429                  * next-header byte and 3-byte alignment at the end.
430                  */
431                 binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4;
432                 hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF);
433                 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
434
435                 cur += sizeof(struct opt_hdr_v1);
436
437                 args = cur;
438                 *args = cpu_to_le32(binarye->binary.nargs);
439                 args++;
440                 for (argi = 0; argi < binarye->binary.nargs; argi++)
441                         args[argi] = cpu_to_le32(binarye->binary.args[argi]);
442
443                 cur += (binarye->binary.nargs + 1) * sizeof(uint32_t);
444
445                 ret = fread(cur, s.st_size, 1, bin);
446                 if (ret != 1) {
447                         fprintf(stderr,
448                                 "Could not read binary image %s\n",
449                                 binarye->binary.file);
450                         return NULL;
451                 }
452
453                 fclose(bin);
454
455                 cur += ALIGN_SUP(s.st_size, 4);
456
457                 /*
458                  * For now, we don't support more than one binary
459                  * header, and no other header types are
460                  * supported. So, the binary header is necessarily the
461                  * last one
462                  */
463                 *((uint32_t *)cur) = 0x00000000;
464
465                 cur += sizeof(uint32_t);
466         }
467
468         /* Calculate and set the header checksum */
469         main_hdr->checksum = image_checksum8(main_hdr, headersz);
470
471         *imagesz = headersz;
472         return image;
473 }
474
475 static int image_create_config_parse_oneline(char *line,
476                                              struct image_cfg_element *el)
477 {
478         char *keyword, *saveptr;
479         char deliminiters[] = " \t";
480
481         keyword = strtok_r(line, deliminiters, &saveptr);
482         if (!strcmp(keyword, "VERSION")) {
483                 char *value = strtok_r(NULL, deliminiters, &saveptr);
484                 el->type = IMAGE_CFG_VERSION;
485                 el->version = atoi(value);
486         } else if (!strcmp(keyword, "BOOT_FROM")) {
487                 char *value = strtok_r(NULL, deliminiters, &saveptr);
488                 int ret = image_boot_mode_id(value);
489                 if (ret < 0) {
490                         fprintf(stderr,
491                                 "Invalid boot media '%s'\n", value);
492                         return -1;
493                 }
494                 el->type = IMAGE_CFG_BOOT_FROM;
495                 el->bootfrom = ret;
496         } else if (!strcmp(keyword, "NAND_BLKSZ")) {
497                 char *value = strtok_r(NULL, deliminiters, &saveptr);
498                 el->type = IMAGE_CFG_NAND_BLKSZ;
499                 el->nandblksz = strtoul(value, NULL, 16);
500         } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
501                 char *value = strtok_r(NULL, deliminiters, &saveptr);
502                 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
503                 el->nandbadblklocation =
504                         strtoul(value, NULL, 16);
505         } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
506                 char *value = strtok_r(NULL, deliminiters, &saveptr);
507                 int ret = image_nand_ecc_mode_id(value);
508                 if (ret < 0) {
509                         fprintf(stderr,
510                                 "Invalid NAND ECC mode '%s'\n", value);
511                         return -1;
512                 }
513                 el->type = IMAGE_CFG_NAND_ECC_MODE;
514                 el->nandeccmode = ret;
515         } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
516                 char *value = strtok_r(NULL, deliminiters, &saveptr);
517                 el->type = IMAGE_CFG_NAND_PAGESZ;
518                 el->nandpagesz = strtoul(value, NULL, 16);
519         } else if (!strcmp(keyword, "BINARY")) {
520                 char *value = strtok_r(NULL, deliminiters, &saveptr);
521                 int argi = 0;
522
523                 el->type = IMAGE_CFG_BINARY;
524                 el->binary.file = strdup(value);
525                 while (1) {
526                         value = strtok_r(NULL, deliminiters, &saveptr);
527                         if (!value)
528                                 break;
529                         el->binary.args[argi] = strtoul(value, NULL, 16);
530                         argi++;
531                         if (argi >= BINARY_MAX_ARGS) {
532                                 fprintf(stderr,
533                                         "Too many argument for binary\n");
534                                 return -1;
535                         }
536                 }
537                 el->binary.nargs = argi;
538         } else if (!strcmp(keyword, "DATA")) {
539                 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
540                 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
541
542                 if (!value1 || !value2) {
543                         fprintf(stderr,
544                                 "Invalid number of arguments for DATA\n");
545                         return -1;
546                 }
547
548                 el->type = IMAGE_CFG_DATA;
549                 el->regdata.raddr = strtoul(value1, NULL, 16);
550                 el->regdata.rdata = strtoul(value2, NULL, 16);
551         } else {
552                 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
553         }
554
555         return 0;
556 }
557
558 /*
559  * Parse the configuration file 'fcfg' into the array of configuration
560  * elements 'image_cfg', and return the number of configuration
561  * elements in 'cfgn'.
562  */
563 static int image_create_config_parse(FILE *fcfg)
564 {
565         int ret;
566         int cfgi = 0;
567
568         /* Parse the configuration file */
569         while (!feof(fcfg)) {
570                 char *line;
571                 char buf[256];
572
573                 /* Read the current line */
574                 memset(buf, 0, sizeof(buf));
575                 line = fgets(buf, sizeof(buf), fcfg);
576                 if (!line)
577                         break;
578
579                 /* Ignore useless lines */
580                 if (line[0] == '\n' || line[0] == '#')
581                         continue;
582
583                 /* Strip final newline */
584                 if (line[strlen(line) - 1] == '\n')
585                         line[strlen(line) - 1] = 0;
586
587                 /* Parse the current line */
588                 ret = image_create_config_parse_oneline(line,
589                                                         &image_cfg[cfgi]);
590                 if (ret)
591                         return ret;
592
593                 cfgi++;
594
595                 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
596                         fprintf(stderr,
597                                 "Too many configuration elements in .cfg file\n");
598                         return -1;
599                 }
600         }
601
602         cfgn = cfgi;
603         return 0;
604 }
605
606 static int image_get_version(void)
607 {
608         struct image_cfg_element *e;
609
610         e = image_find_option(IMAGE_CFG_VERSION);
611         if (!e)
612                 return -1;
613
614         return e->version;
615 }
616
617 static int image_version_file(const char *input)
618 {
619         FILE *fcfg;
620         int version;
621         int ret;
622
623         fcfg = fopen(input, "r");
624         if (!fcfg) {
625                 fprintf(stderr, "Could not open input file %s\n", input);
626                 return -1;
627         }
628
629         image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
630                            sizeof(struct image_cfg_element));
631         if (!image_cfg) {
632                 fprintf(stderr, "Cannot allocate memory\n");
633                 fclose(fcfg);
634                 return -1;
635         }
636
637         memset(image_cfg, 0,
638                IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
639         rewind(fcfg);
640
641         ret = image_create_config_parse(fcfg);
642         fclose(fcfg);
643         if (ret) {
644                 free(image_cfg);
645                 return -1;
646         }
647
648         version = image_get_version();
649         /* Fallback to version 0 is no version is provided in the cfg file */
650         if (version == -1)
651                 version = 0;
652
653         free(image_cfg);
654
655         return version;
656 }
657
658 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
659                                 struct image_tool_params *params)
660 {
661         FILE *fcfg;
662         void *image = NULL;
663         int version;
664         size_t headersz = 0;
665         uint32_t checksum;
666         int ret;
667         int size;
668
669         fcfg = fopen(params->imagename, "r");
670         if (!fcfg) {
671                 fprintf(stderr, "Could not open input file %s\n",
672                         params->imagename);
673                 exit(EXIT_FAILURE);
674         }
675
676         image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
677                            sizeof(struct image_cfg_element));
678         if (!image_cfg) {
679                 fprintf(stderr, "Cannot allocate memory\n");
680                 fclose(fcfg);
681                 exit(EXIT_FAILURE);
682         }
683
684         memset(image_cfg, 0,
685                IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
686         rewind(fcfg);
687
688         ret = image_create_config_parse(fcfg);
689         fclose(fcfg);
690         if (ret) {
691                 free(image_cfg);
692                 exit(EXIT_FAILURE);
693         }
694
695         /* The MVEBU BootROM does not allow non word aligned payloads */
696         sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
697
698         version = image_get_version();
699         switch (version) {
700                 /*
701                  * Fallback to version 0 if no version is provided in the
702                  * cfg file
703                  */
704         case -1:
705         case 0:
706                 image = image_create_v0(&headersz, params, sbuf->st_size);
707                 break;
708
709         case 1:
710                 image = image_create_v1(&headersz, params, sbuf->st_size);
711                 break;
712
713         default:
714                 fprintf(stderr, "Unsupported version %d\n", version);
715                 free(image_cfg);
716                 exit(EXIT_FAILURE);
717         }
718
719         if (!image) {
720                 fprintf(stderr, "Could not create image\n");
721                 free(image_cfg);
722                 exit(EXIT_FAILURE);
723         }
724
725         free(image_cfg);
726
727         /* Build and add image checksum header */
728         checksum =
729                 cpu_to_le32(image_checksum32((uint32_t *)ptr, sbuf->st_size));
730         size = write(ifd, &checksum, sizeof(uint32_t));
731         if (size != sizeof(uint32_t)) {
732                 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
733                         params->cmdname, size, params->imagefile);
734                 exit(EXIT_FAILURE);
735         }
736
737         sbuf->st_size += sizeof(uint32_t);
738
739         /* Finally copy the header into the image area */
740         memcpy(ptr, image, headersz);
741
742         free(image);
743 }
744
745 static void kwbimage_print_header(const void *ptr)
746 {
747         struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
748
749         printf("Image Type:   MVEBU Boot from %s Image\n",
750                image_boot_mode_name(mhdr->blockid));
751         printf("Image version:%d\n", image_version((void *)ptr));
752         printf("Data Size:    ");
753         genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
754         printf("Load Address: %08x\n", mhdr->destaddr);
755         printf("Entry Point:  %08x\n", mhdr->execaddr);
756 }
757
758 static int kwbimage_check_image_types(uint8_t type)
759 {
760         if (type == IH_TYPE_KWBIMAGE)
761                 return EXIT_SUCCESS;
762         else
763                 return EXIT_FAILURE;
764 }
765
766 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
767                                   struct image_tool_params *params)
768 {
769         struct main_hdr_v0 *main_hdr;
770         struct ext_hdr_v0 *ext_hdr;
771         uint8_t checksum;
772
773         main_hdr = (void *)ptr;
774         checksum = image_checksum8(ptr,
775                                    sizeof(struct main_hdr_v0)
776                                    - sizeof(uint8_t));
777         if (checksum != main_hdr->checksum)
778                 return -FDT_ERR_BADSTRUCTURE;
779
780         /* Only version 0 extended header has checksum */
781         if (image_version((void *)ptr) == 0) {
782                 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
783                 checksum = image_checksum8(ext_hdr,
784                                            sizeof(struct ext_hdr_v0)
785                                            - sizeof(uint8_t));
786                 if (checksum != ext_hdr->checksum)
787                         return -FDT_ERR_BADSTRUCTURE;
788         }
789
790         return 0;
791 }
792
793 static int kwbimage_generate(struct image_tool_params *params,
794                              struct image_type_params *tparams)
795 {
796         int alloc_len;
797         void *hdr;
798         int version = 0;
799
800         version = image_version_file(params->imagename);
801         if (version == 0) {
802                 alloc_len = sizeof(struct main_hdr_v0) +
803                         sizeof(struct ext_hdr_v0);
804         } else {
805                 alloc_len = image_headersz_v1(params, NULL);
806         }
807
808         hdr = malloc(alloc_len);
809         if (!hdr) {
810                 fprintf(stderr, "%s: malloc return failure: %s\n",
811                         params->cmdname, strerror(errno));
812                 exit(EXIT_FAILURE);
813         }
814
815         memset(hdr, 0, alloc_len);
816         tparams->header_size = alloc_len;
817         tparams->hdr = hdr;
818
819         /*
820          * The resulting image needs to be 4-byte aligned. At least
821          * the Marvell hdrparser tool complains if its unaligned.
822          * By returning 1 here in this function, called via
823          * tparams->vrec_header() in mkimage.c, mkimage will
824          * automatically pad the the resulting image to a 4-byte
825          * size if necessary.
826          */
827         return 1;
828 }
829
830 /*
831  * Report Error if xflag is set in addition to default
832  */
833 static int kwbimage_check_params(struct image_tool_params *params)
834 {
835         if (!strlen(params->imagename)) {
836                 fprintf(stderr, "Error:%s - Configuration file not specified, "
837                         "it is needed for kwbimage generation\n",
838                         params->cmdname);
839                 return CFG_INVALID;
840         }
841
842         return (params->dflag && (params->fflag || params->lflag)) ||
843                 (params->fflag && (params->dflag || params->lflag)) ||
844                 (params->lflag && (params->dflag || params->fflag)) ||
845                 (params->xflag) || !(strlen(params->imagename));
846 }
847
848 /*
849  * kwbimage type parameters definition
850  */
851 U_BOOT_IMAGE_TYPE(
852         kwbimage,
853         "Marvell MVEBU Boot Image support",
854         0,
855         NULL,
856         kwbimage_check_params,
857         kwbimage_verify_header,
858         kwbimage_print_header,
859         kwbimage_set_header,
860         NULL,
861         kwbimage_check_image_types,
862         NULL,
863         kwbimage_generate
864 );