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