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