]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - tools/kwbimage.c
tools: kwbimage: Support u-boot.img padding to CONFIG_SYS_SPI_U_BOOT_OFFS
[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 #include <config.h>
20
21 #define ALIGN_SUP(x, a) (((x) + (a - 1)) & ~(a - 1))
22
23 /* Structure of the main header, version 0 (Kirkwood, Dove) */
24 struct main_hdr_v0 {
25         uint8_t  blockid;               /*0     */
26         uint8_t  nandeccmode;           /*1     */
27         uint16_t nandpagesize;          /*2-3   */
28         uint32_t blocksize;             /*4-7   */
29         uint32_t rsvd1;                 /*8-11  */
30         uint32_t srcaddr;               /*12-15 */
31         uint32_t destaddr;              /*16-19 */
32         uint32_t execaddr;              /*20-23 */
33         uint8_t  satapiomode;           /*24    */
34         uint8_t  rsvd3;                 /*25    */
35         uint16_t ddrinitdelay;          /*26-27 */
36         uint16_t rsvd2;                 /*28-29 */
37         uint8_t  ext;                   /*30    */
38         uint8_t  checksum;              /*31    */
39 };
40
41 struct ext_hdr_v0_reg {
42         uint32_t raddr;
43         uint32_t rdata;
44 };
45
46 #define EXT_HDR_V0_REG_COUNT ((0x1dc - 0x20) / sizeof(struct ext_hdr_v0_reg))
47
48 struct ext_hdr_v0 {
49         uint32_t              offset;
50         uint8_t               reserved[0x20 - sizeof(uint32_t)];
51         struct ext_hdr_v0_reg rcfg[EXT_HDR_V0_REG_COUNT];
52         uint8_t               reserved2[7];
53         uint8_t               checksum;
54 };
55
56 /* Structure of the main header, version 1 (Armada 370, Armada XP) */
57 struct main_hdr_v1 {
58         uint8_t  blockid;               /* 0 */
59         uint8_t  reserved1;             /* 1 */
60         uint16_t reserved2;             /* 2-3 */
61         uint32_t blocksize;             /* 4-7 */
62         uint8_t  version;               /* 8 */
63         uint8_t  headersz_msb;          /* 9 */
64         uint16_t headersz_lsb;          /* A-B */
65         uint32_t srcaddr;               /* C-F */
66         uint32_t destaddr;              /* 10-13 */
67         uint32_t execaddr;              /* 14-17 */
68         uint8_t  reserved3;             /* 18 */
69         uint8_t  nandblocksize;         /* 19 */
70         uint8_t  nandbadblklocation;    /* 1A */
71         uint8_t  reserved4;             /* 1B */
72         uint16_t reserved5;             /* 1C-1D */
73         uint8_t  ext;                   /* 1E */
74         uint8_t  checksum;              /* 1F */
75 };
76
77 /*
78  * Header for the optional headers, version 1 (Armada 370, Armada XP)
79  */
80 struct opt_hdr_v1 {
81         uint8_t  headertype;
82         uint8_t  headersz_msb;
83         uint16_t headersz_lsb;
84         char     data[0];
85 };
86
87 /*
88  * Various values for the opt_hdr_v1->headertype field, describing the
89  * different types of optional headers. The "secure" header contains
90  * informations related to secure boot (encryption keys, etc.). The
91  * "binary" header contains ARM binary code to be executed prior to
92  * executing the main payload (usually the bootloader). This is
93  * typically used to execute DDR3 training code. The "register" header
94  * allows to describe a set of (address, value) tuples that are
95  * generally used to configure the DRAM controller.
96  */
97 #define OPT_HDR_V1_SECURE_TYPE   0x1
98 #define OPT_HDR_V1_BINARY_TYPE   0x2
99 #define OPT_HDR_V1_REGISTER_TYPE 0x3
100
101 #define KWBHEADER_V1_SIZE(hdr) \
102         (((hdr)->headersz_msb << 16) | (hdr)->headersz_lsb)
103
104 static struct image_cfg_element *image_cfg;
105 static int cfgn;
106
107 struct boot_mode {
108         unsigned int id;
109         const char *name;
110 };
111
112 struct boot_mode boot_modes[] = {
113         { 0x4D, "i2c"  },
114         { 0x5A, "spi"  },
115         { 0x8B, "nand" },
116         { 0x78, "sata" },
117         { 0x9C, "pex"  },
118         { 0x69, "uart" },
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         /*
425          * The payload should be aligned on some reasonable
426          * boundary
427          */
428         return ALIGN_SUP(headersz, 4096);
429 }
430
431 static void *image_create_v1(size_t *imagesz, struct image_tool_params *params,
432                              int payloadsz)
433 {
434         struct image_cfg_element *e, *binarye;
435         struct main_hdr_v1 *main_hdr;
436         size_t headersz;
437         void *image, *cur;
438         int hasext = 0;
439         int ret;
440
441         /*
442          * Calculate the size of the header and the size of the
443          * payload
444          */
445         headersz = image_headersz_v1(params, &hasext);
446         if (headersz == 0)
447                 return NULL;
448
449         image = malloc(headersz);
450         if (!image) {
451                 fprintf(stderr, "Cannot allocate memory for image\n");
452                 return NULL;
453         }
454
455         memset(image, 0, headersz);
456
457         cur = main_hdr = image;
458         cur += sizeof(struct main_hdr_v1);
459
460         /* Fill the main header */
461         main_hdr->blocksize    = payloadsz - headersz + sizeof(uint32_t);
462         main_hdr->headersz_lsb = headersz & 0xFFFF;
463         main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16;
464         main_hdr->destaddr     = params->addr;
465         main_hdr->execaddr     = params->ep;
466         main_hdr->srcaddr      = headersz;
467         main_hdr->ext          = hasext;
468         main_hdr->version      = 1;
469         e = image_find_option(IMAGE_CFG_BOOT_FROM);
470         if (e)
471                 main_hdr->blockid = e->bootfrom;
472         e = image_find_option(IMAGE_CFG_NAND_BLKSZ);
473         if (e)
474                 main_hdr->nandblocksize = e->nandblksz / (64 * 1024);
475         e = image_find_option(IMAGE_CFG_NAND_BADBLK_LOCATION);
476         if (e)
477                 main_hdr->nandbadblklocation = e->nandbadblklocation;
478
479         binarye = image_find_option(IMAGE_CFG_BINARY);
480         if (binarye) {
481                 struct opt_hdr_v1 *hdr = cur;
482                 unsigned int *args;
483                 size_t binhdrsz;
484                 struct stat s;
485                 int argi;
486                 FILE *bin;
487
488                 hdr->headertype = OPT_HDR_V1_BINARY_TYPE;
489
490                 bin = fopen(binarye->binary.file, "r");
491                 if (!bin) {
492                         fprintf(stderr, "Cannot open binary file %s\n",
493                                 binarye->binary.file);
494                         return NULL;
495                 }
496
497                 fstat(fileno(bin), &s);
498
499                 binhdrsz = sizeof(struct opt_hdr_v1) +
500                         (binarye->binary.nargs + 1) * sizeof(unsigned int) +
501                         s.st_size;
502                 hdr->headersz_lsb = binhdrsz & 0xFFFF;
503                 hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
504
505                 cur += sizeof(struct opt_hdr_v1);
506
507                 args = cur;
508                 *args = binarye->binary.nargs;
509                 args++;
510                 for (argi = 0; argi < binarye->binary.nargs; argi++)
511                         args[argi] = binarye->binary.args[argi];
512
513                 cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
514
515                 ret = fread(cur, s.st_size, 1, bin);
516                 if (ret != 1) {
517                         fprintf(stderr,
518                                 "Could not read binary image %s\n",
519                                 binarye->binary.file);
520                         return NULL;
521                 }
522
523                 fclose(bin);
524
525                 cur += s.st_size;
526
527                 /*
528                  * For now, we don't support more than one binary
529                  * header, and no other header types are
530                  * supported. So, the binary header is necessarily the
531                  * last one
532                  */
533                 *((unsigned char *)cur) = 0;
534
535                 cur += sizeof(uint32_t);
536         }
537
538         /* Calculate and set the header checksum */
539         main_hdr->checksum = image_checksum8(main_hdr, headersz);
540
541         *imagesz = headersz;
542         return image;
543 }
544
545 static int image_create_config_parse_oneline(char *line,
546                                              struct image_cfg_element *el)
547 {
548         char *keyword, *saveptr;
549         char deliminiters[] = " \t";
550
551         keyword = strtok_r(line, deliminiters, &saveptr);
552         if (!strcmp(keyword, "VERSION")) {
553                 char *value = strtok_r(NULL, deliminiters, &saveptr);
554                 el->type = IMAGE_CFG_VERSION;
555                 el->version = atoi(value);
556         } else if (!strcmp(keyword, "BOOT_FROM")) {
557                 char *value = strtok_r(NULL, deliminiters, &saveptr);
558                 int ret = image_boot_mode_id(value);
559                 if (ret < 0) {
560                         fprintf(stderr,
561                                 "Invalid boot media '%s'\n", value);
562                         return -1;
563                 }
564                 el->type = IMAGE_CFG_BOOT_FROM;
565                 el->bootfrom = ret;
566         } else if (!strcmp(keyword, "NAND_BLKSZ")) {
567                 char *value = strtok_r(NULL, deliminiters, &saveptr);
568                 el->type = IMAGE_CFG_NAND_BLKSZ;
569                 el->nandblksz = strtoul(value, NULL, 16);
570         } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
571                 char *value = strtok_r(NULL, deliminiters, &saveptr);
572                 el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
573                 el->nandbadblklocation =
574                         strtoul(value, NULL, 16);
575         } else if (!strcmp(keyword, "NAND_ECC_MODE")) {
576                 char *value = strtok_r(NULL, deliminiters, &saveptr);
577                 int ret = image_nand_ecc_mode_id(value);
578                 if (ret < 0) {
579                         fprintf(stderr,
580                                 "Invalid NAND ECC mode '%s'\n", value);
581                         return -1;
582                 }
583                 el->type = IMAGE_CFG_NAND_ECC_MODE;
584                 el->nandeccmode = ret;
585         } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
586                 char *value = strtok_r(NULL, deliminiters, &saveptr);
587                 el->type = IMAGE_CFG_NAND_PAGESZ;
588                 el->nandpagesz = strtoul(value, NULL, 16);
589         } else if (!strcmp(keyword, "BINARY")) {
590                 char *value = strtok_r(NULL, deliminiters, &saveptr);
591                 int argi = 0;
592
593                 el->type = IMAGE_CFG_BINARY;
594                 el->binary.file = strdup(value);
595                 while (1) {
596                         value = strtok_r(NULL, deliminiters, &saveptr);
597                         if (!value)
598                                 break;
599                         el->binary.args[argi] = strtoul(value, NULL, 16);
600                         argi++;
601                         if (argi >= BINARY_MAX_ARGS) {
602                                 fprintf(stderr,
603                                         "Too many argument for binary\n");
604                                 return -1;
605                         }
606                 }
607                 el->binary.nargs = argi;
608         } else if (!strcmp(keyword, "DATA")) {
609                 char *value1 = strtok_r(NULL, deliminiters, &saveptr);
610                 char *value2 = strtok_r(NULL, deliminiters, &saveptr);
611
612                 if (!value1 || !value2) {
613                         fprintf(stderr,
614                                 "Invalid number of arguments for DATA\n");
615                         return -1;
616                 }
617
618                 el->type = IMAGE_CFG_DATA;
619                 el->regdata.raddr = strtoul(value1, NULL, 16);
620                 el->regdata.rdata = strtoul(value2, NULL, 16);
621         } else {
622                 fprintf(stderr, "Ignoring unknown line '%s'\n", line);
623         }
624
625         return 0;
626 }
627
628 /*
629  * Parse the configuration file 'fcfg' into the array of configuration
630  * elements 'image_cfg', and return the number of configuration
631  * elements in 'cfgn'.
632  */
633 static int image_create_config_parse(FILE *fcfg)
634 {
635         int ret;
636         int cfgi = 0;
637
638         /* Parse the configuration file */
639         while (!feof(fcfg)) {
640                 char *line;
641                 char buf[256];
642
643                 /* Read the current line */
644                 memset(buf, 0, sizeof(buf));
645                 line = fgets(buf, sizeof(buf), fcfg);
646                 if (!line)
647                         break;
648
649                 /* Ignore useless lines */
650                 if (line[0] == '\n' || line[0] == '#')
651                         continue;
652
653                 /* Strip final newline */
654                 if (line[strlen(line) - 1] == '\n')
655                         line[strlen(line) - 1] = 0;
656
657                 /* Parse the current line */
658                 ret = image_create_config_parse_oneline(line,
659                                                         &image_cfg[cfgi]);
660                 if (ret)
661                         return ret;
662
663                 cfgi++;
664
665                 if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
666                         fprintf(stderr,
667                                 "Too many configuration elements in .cfg file\n");
668                         return -1;
669                 }
670         }
671
672         cfgn = cfgi;
673         return 0;
674 }
675
676 static int image_get_version(void)
677 {
678         struct image_cfg_element *e;
679
680         e = image_find_option(IMAGE_CFG_VERSION);
681         if (!e)
682                 return -1;
683
684         return e->version;
685 }
686
687 static int image_version_file(const char *input)
688 {
689         FILE *fcfg;
690         int version;
691         int ret;
692
693         fcfg = fopen(input, "r");
694         if (!fcfg) {
695                 fprintf(stderr, "Could not open input file %s\n", input);
696                 return -1;
697         }
698
699         image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
700                            sizeof(struct image_cfg_element));
701         if (!image_cfg) {
702                 fprintf(stderr, "Cannot allocate memory\n");
703                 fclose(fcfg);
704                 return -1;
705         }
706
707         memset(image_cfg, 0,
708                IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
709         rewind(fcfg);
710
711         ret = image_create_config_parse(fcfg);
712         fclose(fcfg);
713         if (ret) {
714                 free(image_cfg);
715                 return -1;
716         }
717
718         version = image_get_version();
719         /* Fallback to version 0 is no version is provided in the cfg file */
720         if (version == -1)
721                 version = 0;
722
723         free(image_cfg);
724
725         return version;
726 }
727
728 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
729                                 struct image_tool_params *params)
730 {
731         FILE *fcfg;
732         void *image = NULL;
733         int version;
734         size_t headersz = 0;
735         uint32_t checksum;
736         int ret;
737         int size;
738
739         fcfg = fopen(params->imagename, "r");
740         if (!fcfg) {
741                 fprintf(stderr, "Could not open input file %s\n",
742                         params->imagename);
743                 exit(EXIT_FAILURE);
744         }
745
746         image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
747                            sizeof(struct image_cfg_element));
748         if (!image_cfg) {
749                 fprintf(stderr, "Cannot allocate memory\n");
750                 fclose(fcfg);
751                 exit(EXIT_FAILURE);
752         }
753
754         memset(image_cfg, 0,
755                IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
756         rewind(fcfg);
757
758         ret = image_create_config_parse(fcfg);
759         fclose(fcfg);
760         if (ret) {
761                 free(image_cfg);
762                 exit(EXIT_FAILURE);
763         }
764
765         version = image_get_version();
766         switch (version) {
767                 /*
768                  * Fallback to version 0 if no version is provided in the
769                  * cfg file
770                  */
771         case -1:
772         case 0:
773                 image = image_create_v0(&headersz, params, sbuf->st_size);
774                 break;
775
776         case 1:
777                 image = image_create_v1(&headersz, params, sbuf->st_size);
778                 break;
779
780         default:
781                 fprintf(stderr, "Unsupported version %d\n", version);
782                 free(image_cfg);
783                 exit(EXIT_FAILURE);
784         }
785
786         if (!image) {
787                 fprintf(stderr, "Could not create image\n");
788                 free(image_cfg);
789                 exit(EXIT_FAILURE);
790         }
791
792         free(image_cfg);
793
794         /* Build and add image checksum header */
795         checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
796         size = write(ifd, &checksum, sizeof(uint32_t));
797         if (size != sizeof(uint32_t)) {
798                 fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
799                         params->cmdname, size, params->imagefile);
800                 exit(EXIT_FAILURE);
801         }
802
803         sbuf->st_size += sizeof(uint32_t);
804
805         /* Finally copy the header into the image area */
806         memcpy(ptr, image, headersz);
807
808         free(image);
809 }
810
811 static void kwbimage_print_header(const void *ptr)
812 {
813         struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
814
815         printf("Image Type:   MVEBU Boot from %s Image\n",
816                image_boot_mode_name(mhdr->blockid));
817         printf("Image version:%d\n", image_version((void *)ptr));
818         printf("Data Size:    ");
819         genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
820         printf("Load Address: %08x\n", mhdr->destaddr);
821         printf("Entry Point:  %08x\n", mhdr->execaddr);
822 }
823
824 static int kwbimage_check_image_types(uint8_t type)
825 {
826         if (type == IH_TYPE_KWBIMAGE)
827                 return EXIT_SUCCESS;
828         else
829                 return EXIT_FAILURE;
830 }
831
832 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
833                                   struct image_tool_params *params)
834 {
835         struct main_hdr_v0 *main_hdr;
836         struct ext_hdr_v0 *ext_hdr;
837         uint8_t checksum;
838
839         main_hdr = (void *)ptr;
840         checksum = image_checksum8(ptr,
841                                    sizeof(struct main_hdr_v0)
842                                    - sizeof(uint8_t));
843         if (checksum != main_hdr->checksum)
844                 return -FDT_ERR_BADSTRUCTURE;
845
846         /* Only version 0 extended header has checksum */
847         if (image_version((void *)ptr) == 0) {
848                 ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
849                 checksum = image_checksum8(ext_hdr,
850                                            sizeof(struct ext_hdr_v0)
851                                            - sizeof(uint8_t));
852                 if (checksum != ext_hdr->checksum)
853                         return -FDT_ERR_BADSTRUCTURE;
854         }
855
856         return 0;
857 }
858
859 static int kwbimage_generate(struct image_tool_params *params,
860                              struct image_type_params *tparams)
861 {
862         int alloc_len;
863         void *hdr;
864         int version = 0;
865
866         version = image_version_file(params->imagename);
867         if (version == 0) {
868                 alloc_len = sizeof(struct main_hdr_v0) +
869                         sizeof(struct ext_hdr_v0);
870         } else {
871                 alloc_len = image_headersz_v1(params, NULL);
872 #if defined(CONFIG_SYS_SPI_U_BOOT_OFFS)
873                 if (alloc_len > CONFIG_SYS_SPI_U_BOOT_OFFS) {
874                         fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n");
875                         fprintf(stderr, "header=0x%x CONFIG_SYS_SPI_U_BOOT_OFFS=0x%x!\n",
876                                 alloc_len, CONFIG_SYS_SPI_U_BOOT_OFFS);
877                         fprintf(stderr, "Increase CONFIG_SYS_SPI_U_BOOT_OFFS!\n");
878                 } else {
879                         alloc_len = CONFIG_SYS_SPI_U_BOOT_OFFS;
880                 }
881 #endif
882         }
883
884         hdr = malloc(alloc_len);
885         if (!hdr) {
886                 fprintf(stderr, "%s: malloc return failure: %s\n",
887                         params->cmdname, strerror(errno));
888                 exit(EXIT_FAILURE);
889         }
890
891         memset(hdr, 0, alloc_len);
892         tparams->header_size = alloc_len;
893         tparams->hdr = hdr;
894
895         return 0;
896 }
897
898 /*
899  * Report Error if xflag is set in addition to default
900  */
901 static int kwbimage_check_params(struct image_tool_params *params)
902 {
903         if (!strlen(params->imagename)) {
904                 fprintf(stderr, "Error:%s - Configuration file not specified, "
905                         "it is needed for kwbimage generation\n",
906                         params->cmdname);
907                 return CFG_INVALID;
908         }
909
910         return (params->dflag && (params->fflag || params->lflag)) ||
911                 (params->fflag && (params->dflag || params->lflag)) ||
912                 (params->lflag && (params->dflag || params->fflag)) ||
913                 (params->xflag) || !(strlen(params->imagename));
914 }
915
916 /*
917  * kwbimage type parameters definition
918  */
919 U_BOOT_IMAGE_TYPE(
920         kwbimage,
921         "Marvell MVEBU Boot Image support",
922         0,
923         NULL,
924         kwbimage_check_params,
925         kwbimage_verify_header,
926         kwbimage_print_header,
927         kwbimage_set_header,
928         NULL,
929         kwbimage_check_image_types,
930         NULL,
931         kwbimage_generate
932 );