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