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