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