]> git.sur5r.net Git - u-boot/blob - tools/kwbimage.c
Merge branch 'patman' of git://git.denx.de/u-boot-x86
[u-boot] / 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) - headersz;
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                 int ret = image_boot_mode_id(value);
558                 if (ret < 0) {
559                         fprintf(stderr,
560                                 "Invalid boot media '%s'\n", value);
561                         return -1;
562                 }
563                 el->type = IMAGE_CFG_BOOT_FROM;
564                 el->bootfrom = ret;
565         } else if (!strcmp(keyword, "NAND_BLKSZ")) {
566                 char *value = strtok_r(NULL, deliminiters, &saveptr);
567                 el->type = IMAGE_CFG_NAND_BLKSZ;
568                 el->nandblksz = strtoul(value, NULL, 16);
569         } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
570                 char *value = strtok_r(NULL, deliminiters, &saveptr);
571                 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
572                 el->nandbadblklocation =
573                         strtoul(value, NULL, 16);
574         } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
575                 char *value = strtok_r(NULL, deliminiters, &saveptr);
576                 int ret = image_nand_ecc_mode_id(value);
577                 if (ret < 0) {
578                         fprintf(stderr,
579                                 "Invalid NAND ECC mode '%s'\n", value);
580                         return -1;
581                 }
582                 el->type = IMAGE_CFG_NAND_ECC_MODE;
583                 el->nandeccmode = ret;
584         } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
585                 char *value = strtok_r(NULL, deliminiters, &saveptr);
586                 el->type = IMAGE_CFG_NAND_PAGESZ;
587                 el->nandpagesz = strtoul(value, NULL, 16);
588         } else if (!strcmp(keyword, "BINARY")) {
589                 char *value = strtok_r(NULL, deliminiters, &saveptr);
590                 int argi = 0;
591
592                 el->type = IMAGE_CFG_BINARY;
593                 el->binary.file = strdup(value);
594                 while (1) {
595                         value = strtok_r(NULL, deliminiters, &saveptr);
596                         if (!value)
597                                 break;
598                         el->binary.args[argi] = strtoul(value, NULL, 16);
599                         argi++;
600                         if (argi >= BINARY_MAX_ARGS) {
601                                 fprintf(stderr,
602                                         "Too many argument for binary\n");
603                                 return -1;
604                         }
605                 }
606                 el->binary.nargs = argi;
607         } else if (!strcmp(keyword, "DATA")) {
608                 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
609                 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
610
611                 if (!value1 || !value2) {
612                         fprintf(stderr,
613                                 "Invalid number of arguments for DATA\n");
614                         return -1;
615                 }
616
617                 el->type = IMAGE_CFG_DATA;
618                 el->regdata.raddr = strtoul(value1, NULL, 16);
619                 el->regdata.rdata = strtoul(value2, NULL, 16);
620         } else {
621                 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
622         }
623
624         return 0;
625 }
626
627 /*
628  * Parse the configuration file 'fcfg' into the array of configuration
629  * elements 'image_cfg', and return the number of configuration
630  * elements in 'cfgn'.
631  */
632 static int image_create_config_parse(FILE *fcfg)
633 {
634         int ret;
635         int cfgi = 0;
636
637         /* Parse the configuration file */
638         while (!feof(fcfg)) {
639                 char *line;
640                 char buf[256];
641
642                 /* Read the current line */
643                 memset(buf, 0, sizeof(buf));
644                 line = fgets(buf, sizeof(buf), fcfg);
645                 if (!line)
646                         break;
647
648                 /* Ignore useless lines */
649                 if (line[0] == '\n' || line[0] == '#')
650                         continue;
651
652                 /* Strip final newline */
653                 if (line[strlen(line) - 1] == '\n')
654                         line[strlen(line) - 1] = 0;
655
656                 /* Parse the current line */
657                 ret = image_create_config_parse_oneline(line,
658                                                         &image_cfg[cfgi]);
659                 if (ret)
660                         return ret;
661
662                 cfgi++;
663
664                 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
665                         fprintf(stderr,
666                                 "Too many configuration elements in .cfg file\n");
667                         return -1;
668                 }
669         }
670
671         cfgn = cfgi;
672         return 0;
673 }
674
675 static int image_get_version(void)
676 {
677         struct image_cfg_element *e;
678
679         e = image_find_option(IMAGE_CFG_VERSION);
680         if (!e)
681                 return -1;
682
683         return e->version;
684 }
685
686 static int image_version_file(const char *input)
687 {
688         FILE *fcfg;
689         int version;
690         int ret;
691
692         fcfg = fopen(input, "r");
693         if (!fcfg) {
694                 fprintf(stderr, "Could not open input file %s\n", input);
695                 return -1;
696         }
697
698         image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
699                            sizeof(struct image_cfg_element));
700         if (!image_cfg) {
701                 fprintf(stderr, "Cannot allocate memory\n");
702                 fclose(fcfg);
703                 return -1;
704         }
705
706         memset(image_cfg, 0,
707                IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
708         rewind(fcfg);
709
710         ret = image_create_config_parse(fcfg);
711         fclose(fcfg);
712         if (ret) {
713                 free(image_cfg);
714                 return -1;
715         }
716
717         version = image_get_version();
718         /* Fallback to version 0 is no version is provided in the cfg file */
719         if (version == -1)
720                 version = 0;
721
722         free(image_cfg);
723
724         return version;
725 }
726
727 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
728                                 struct image_tool_params *params)
729 {
730         FILE *fcfg;
731         void *image = NULL;
732         int version;
733         size_t headersz = 0;
734         uint32_t checksum;
735         int ret;
736         int size;
737
738         fcfg = fopen(params->imagename, "r");
739         if (!fcfg) {
740                 fprintf(stderr, "Could not open input file %s\n",
741                         params->imagename);
742                 exit(EXIT_FAILURE);
743         }
744
745         image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
746                            sizeof(struct image_cfg_element));
747         if (!image_cfg) {
748                 fprintf(stderr, "Cannot allocate memory\n");
749                 fclose(fcfg);
750                 exit(EXIT_FAILURE);
751         }
752
753         memset(image_cfg, 0,
754                IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
755         rewind(fcfg);
756
757         ret = image_create_config_parse(fcfg);
758         fclose(fcfg);
759         if (ret) {
760                 free(image_cfg);
761                 exit(EXIT_FAILURE);
762         }
763
764         version = image_get_version();
765         switch (version) {
766                 /*
767                  * Fallback to version 0 if no version is provided in the
768                  * cfg file
769                  */
770         case -1:
771         case 0:
772                 image = image_create_v0(&headersz, params, sbuf->st_size);
773                 break;
774
775         case 1:
776                 image = image_create_v1(&headersz, params, sbuf->st_size);
777                 break;
778
779         default:
780                 fprintf(stderr, "Unsupported version %d\n", version);
781                 free(image_cfg);
782                 exit(EXIT_FAILURE);
783         }
784
785         if (!image) {
786                 fprintf(stderr, "Could not create image\n");
787                 free(image_cfg);
788                 exit(EXIT_FAILURE);
789         }
790
791         free(image_cfg);
792
793         /* Build and add image checksum header */
794         checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
795         size = write(ifd, &checksum, sizeof(uint32_t));
796         if (size != sizeof(uint32_t)) {
797                 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
798                         params->cmdname, size, params->imagefile);
799                 exit(EXIT_FAILURE);
800         }
801
802         sbuf->st_size += sizeof(uint32_t);
803
804         /* Finally copy the header into the image area */
805         memcpy(ptr, image, headersz);
806
807         free(image);
808 }
809
810 static void kwbimage_print_header(const void *ptr)
811 {
812         struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
813
814         printf("Image Type:   MVEBU Boot from %s Image\n",
815                image_boot_mode_name(mhdr->blockid));
816         printf("Image version:%d\n", image_version((void *)ptr));
817         printf("Data Size:    ");
818         genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
819         printf("Load Address: %08x\n", mhdr->destaddr);
820         printf("Entry Point:  %08x\n", mhdr->execaddr);
821 }
822
823 static int kwbimage_check_image_types(uint8_t type)
824 {
825         if (type == IH_TYPE_KWBIMAGE)
826                 return EXIT_SUCCESS;
827         else
828                 return EXIT_FAILURE;
829 }
830
831 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
832                                   struct image_tool_params *params)
833 {
834         struct main_hdr_v0 *main_hdr;
835         struct ext_hdr_v0 *ext_hdr;
836         uint8_t checksum;
837
838         main_hdr = (void *)ptr;
839         checksum = image_checksum8(ptr,
840                                    sizeof(struct main_hdr_v0)
841                                    - sizeof(uint8_t));
842         if (checksum != main_hdr->checksum)
843                 return -FDT_ERR_BADSTRUCTURE;
844
845         /* Only version 0 extended header has checksum */
846         if (image_version((void *)ptr) == 0) {
847                 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
848                 checksum = image_checksum8(ext_hdr,
849                                            sizeof(struct ext_hdr_v0)
850                                            - sizeof(uint8_t));
851                 if (checksum != ext_hdr->checksum)
852                         return -FDT_ERR_BADSTRUCTURE;
853         }
854
855         return 0;
856 }
857
858 static int kwbimage_generate(struct image_tool_params *params,
859                              struct image_type_params *tparams)
860 {
861         int alloc_len;
862         void *hdr;
863         int version = 0;
864
865         version = image_version_file(params->imagename);
866         if (version == 0) {
867                 alloc_len = sizeof(struct main_hdr_v0) +
868                         sizeof(struct ext_hdr_v0);
869         } else {
870                 alloc_len = image_headersz_v1(params, NULL);
871         }
872
873         hdr = malloc(alloc_len);
874         if (!hdr) {
875                 fprintf(stderr, "%s: malloc return failure: %s\n",
876                         params->cmdname, strerror(errno));
877                 exit(EXIT_FAILURE);
878         }
879
880         memset(hdr, 0, alloc_len);
881         tparams->header_size = alloc_len;
882         tparams->hdr = hdr;
883
884         return 0;
885 }
886
887 /*
888  * Report Error if xflag is set in addition to default
889  */
890 static int kwbimage_check_params(struct image_tool_params *params)
891 {
892         if (!strlen(params->imagename)) {
893                 fprintf(stderr, "Error:%s - Configuration file not specified, "
894                         "it is needed for kwbimage generation\n",
895                         params->cmdname);
896                 return CFG_INVALID;
897         }
898
899         return (params->dflag && (params->fflag || params->lflag)) ||
900                 (params->fflag && (params->dflag || params->lflag)) ||
901                 (params->lflag && (params->dflag || params->fflag)) ||
902                 (params->xflag) || !(strlen(params->imagename));
903 }
904
905 /*
906  * kwbimage type parameters definition
907  */
908 U_BOOT_IMAGE_TYPE(
909         kwbimage,
910         "Marvell MVEBU Boot Image support",
911         0,
912         NULL,
913         kwbimage_check_params,
914         kwbimage_verify_header,
915         kwbimage_print_header,
916         kwbimage_set_header,
917         NULL,
918         kwbimage_check_image_types,
919         NULL,
920         kwbimage_generate
921 );