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