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