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