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