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