xref: /openbmc/u-boot/tools/kwbimage.c (revision 87e29878)
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 		binhdrsz = ALIGN_SUP(binhdrsz, 32);
421 		hdr->headersz_lsb = binhdrsz & 0xFFFF;
422 		hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16;
423 
424 		cur += sizeof(struct opt_hdr_v1);
425 
426 		args = cur;
427 		*args = binarye->binary.nargs;
428 		args++;
429 		for (argi = 0; argi < binarye->binary.nargs; argi++)
430 			args[argi] = binarye->binary.args[argi];
431 
432 		cur += (binarye->binary.nargs + 1) * sizeof(unsigned int);
433 
434 		ret = fread(cur, s.st_size, 1, bin);
435 		if (ret != 1) {
436 			fprintf(stderr,
437 				"Could not read binary image %s\n",
438 				binarye->binary.file);
439 			return NULL;
440 		}
441 
442 		fclose(bin);
443 
444 		cur += s.st_size;
445 
446 		/*
447 		 * For now, we don't support more than one binary
448 		 * header, and no other header types are
449 		 * supported. So, the binary header is necessarily the
450 		 * last one
451 		 */
452 		*((unsigned char *)cur) = 0;
453 
454 		cur += sizeof(uint32_t);
455 	}
456 
457 	/* Calculate and set the header checksum */
458 	main_hdr->checksum = image_checksum8(main_hdr, headersz);
459 
460 	*imagesz = headersz;
461 	return image;
462 }
463 
464 static int image_create_config_parse_oneline(char *line,
465 					     struct image_cfg_element *el)
466 {
467 	char *keyword, *saveptr;
468 	char deliminiters[] = " \t";
469 
470 	keyword = strtok_r(line, deliminiters, &saveptr);
471 	if (!strcmp(keyword, "VERSION")) {
472 		char *value = strtok_r(NULL, deliminiters, &saveptr);
473 		el->type = IMAGE_CFG_VERSION;
474 		el->version = atoi(value);
475 	} else if (!strcmp(keyword, "BOOT_FROM")) {
476 		char *value = strtok_r(NULL, deliminiters, &saveptr);
477 		int ret = image_boot_mode_id(value);
478 		if (ret < 0) {
479 			fprintf(stderr,
480 				"Invalid boot media '%s'\n", value);
481 			return -1;
482 		}
483 		el->type = IMAGE_CFG_BOOT_FROM;
484 		el->bootfrom = ret;
485 	} else if (!strcmp(keyword, "NAND_BLKSZ")) {
486 		char *value = strtok_r(NULL, deliminiters, &saveptr);
487 		el->type = IMAGE_CFG_NAND_BLKSZ;
488 		el->nandblksz = strtoul(value, NULL, 16);
489 	} else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) {
490 		char *value = strtok_r(NULL, deliminiters, &saveptr);
491 		el->type = IMAGE_CFG_NAND_BADBLK_LOCATION;
492 		el->nandbadblklocation =
493 			strtoul(value, NULL, 16);
494 	} else if (!strcmp(keyword, "NAND_ECC_MODE")) {
495 		char *value = strtok_r(NULL, deliminiters, &saveptr);
496 		int ret = image_nand_ecc_mode_id(value);
497 		if (ret < 0) {
498 			fprintf(stderr,
499 				"Invalid NAND ECC mode '%s'\n", value);
500 			return -1;
501 		}
502 		el->type = IMAGE_CFG_NAND_ECC_MODE;
503 		el->nandeccmode = ret;
504 	} else if (!strcmp(keyword, "NAND_PAGE_SIZE")) {
505 		char *value = strtok_r(NULL, deliminiters, &saveptr);
506 		el->type = IMAGE_CFG_NAND_PAGESZ;
507 		el->nandpagesz = strtoul(value, NULL, 16);
508 	} else if (!strcmp(keyword, "BINARY")) {
509 		char *value = strtok_r(NULL, deliminiters, &saveptr);
510 		int argi = 0;
511 
512 		el->type = IMAGE_CFG_BINARY;
513 		el->binary.file = strdup(value);
514 		while (1) {
515 			value = strtok_r(NULL, deliminiters, &saveptr);
516 			if (!value)
517 				break;
518 			el->binary.args[argi] = strtoul(value, NULL, 16);
519 			argi++;
520 			if (argi >= BINARY_MAX_ARGS) {
521 				fprintf(stderr,
522 					"Too many argument for binary\n");
523 				return -1;
524 			}
525 		}
526 		el->binary.nargs = argi;
527 	} else if (!strcmp(keyword, "DATA")) {
528 		char *value1 = strtok_r(NULL, deliminiters, &saveptr);
529 		char *value2 = strtok_r(NULL, deliminiters, &saveptr);
530 
531 		if (!value1 || !value2) {
532 			fprintf(stderr,
533 				"Invalid number of arguments for DATA\n");
534 			return -1;
535 		}
536 
537 		el->type = IMAGE_CFG_DATA;
538 		el->regdata.raddr = strtoul(value1, NULL, 16);
539 		el->regdata.rdata = strtoul(value2, NULL, 16);
540 	} else {
541 		fprintf(stderr, "Ignoring unknown line '%s'\n", line);
542 	}
543 
544 	return 0;
545 }
546 
547 /*
548  * Parse the configuration file 'fcfg' into the array of configuration
549  * elements 'image_cfg', and return the number of configuration
550  * elements in 'cfgn'.
551  */
552 static int image_create_config_parse(FILE *fcfg)
553 {
554 	int ret;
555 	int cfgi = 0;
556 
557 	/* Parse the configuration file */
558 	while (!feof(fcfg)) {
559 		char *line;
560 		char buf[256];
561 
562 		/* Read the current line */
563 		memset(buf, 0, sizeof(buf));
564 		line = fgets(buf, sizeof(buf), fcfg);
565 		if (!line)
566 			break;
567 
568 		/* Ignore useless lines */
569 		if (line[0] == '\n' || line[0] == '#')
570 			continue;
571 
572 		/* Strip final newline */
573 		if (line[strlen(line) - 1] == '\n')
574 			line[strlen(line) - 1] = 0;
575 
576 		/* Parse the current line */
577 		ret = image_create_config_parse_oneline(line,
578 							&image_cfg[cfgi]);
579 		if (ret)
580 			return ret;
581 
582 		cfgi++;
583 
584 		if (cfgi >= IMAGE_CFG_ELEMENT_MAX) {
585 			fprintf(stderr,
586 				"Too many configuration elements in .cfg file\n");
587 			return -1;
588 		}
589 	}
590 
591 	cfgn = cfgi;
592 	return 0;
593 }
594 
595 static int image_get_version(void)
596 {
597 	struct image_cfg_element *e;
598 
599 	e = image_find_option(IMAGE_CFG_VERSION);
600 	if (!e)
601 		return -1;
602 
603 	return e->version;
604 }
605 
606 static int image_version_file(const char *input)
607 {
608 	FILE *fcfg;
609 	int version;
610 	int ret;
611 
612 	fcfg = fopen(input, "r");
613 	if (!fcfg) {
614 		fprintf(stderr, "Could not open input file %s\n", input);
615 		return -1;
616 	}
617 
618 	image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
619 			   sizeof(struct image_cfg_element));
620 	if (!image_cfg) {
621 		fprintf(stderr, "Cannot allocate memory\n");
622 		fclose(fcfg);
623 		return -1;
624 	}
625 
626 	memset(image_cfg, 0,
627 	       IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
628 	rewind(fcfg);
629 
630 	ret = image_create_config_parse(fcfg);
631 	fclose(fcfg);
632 	if (ret) {
633 		free(image_cfg);
634 		return -1;
635 	}
636 
637 	version = image_get_version();
638 	/* Fallback to version 0 is no version is provided in the cfg file */
639 	if (version == -1)
640 		version = 0;
641 
642 	free(image_cfg);
643 
644 	return version;
645 }
646 
647 static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd,
648 				struct image_tool_params *params)
649 {
650 	FILE *fcfg;
651 	void *image = NULL;
652 	int version;
653 	size_t headersz = 0;
654 	uint32_t checksum;
655 	int ret;
656 	int size;
657 
658 	fcfg = fopen(params->imagename, "r");
659 	if (!fcfg) {
660 		fprintf(stderr, "Could not open input file %s\n",
661 			params->imagename);
662 		exit(EXIT_FAILURE);
663 	}
664 
665 	image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX *
666 			   sizeof(struct image_cfg_element));
667 	if (!image_cfg) {
668 		fprintf(stderr, "Cannot allocate memory\n");
669 		fclose(fcfg);
670 		exit(EXIT_FAILURE);
671 	}
672 
673 	memset(image_cfg, 0,
674 	       IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element));
675 	rewind(fcfg);
676 
677 	ret = image_create_config_parse(fcfg);
678 	fclose(fcfg);
679 	if (ret) {
680 		free(image_cfg);
681 		exit(EXIT_FAILURE);
682 	}
683 
684 	/* The MVEBU BootROM does not allow non word aligned payloads */
685 	sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4);
686 
687 	version = image_get_version();
688 	switch (version) {
689 		/*
690 		 * Fallback to version 0 if no version is provided in the
691 		 * cfg file
692 		 */
693 	case -1:
694 	case 0:
695 		image = image_create_v0(&headersz, params, sbuf->st_size);
696 		break;
697 
698 	case 1:
699 		image = image_create_v1(&headersz, params, sbuf->st_size);
700 		break;
701 
702 	default:
703 		fprintf(stderr, "Unsupported version %d\n", version);
704 		free(image_cfg);
705 		exit(EXIT_FAILURE);
706 	}
707 
708 	if (!image) {
709 		fprintf(stderr, "Could not create image\n");
710 		free(image_cfg);
711 		exit(EXIT_FAILURE);
712 	}
713 
714 	free(image_cfg);
715 
716 	/* Build and add image checksum header */
717 	checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
718 	size = write(ifd, &checksum, sizeof(uint32_t));
719 	if (size != sizeof(uint32_t)) {
720 		fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
721 			params->cmdname, size, params->imagefile);
722 		exit(EXIT_FAILURE);
723 	}
724 
725 	sbuf->st_size += sizeof(uint32_t);
726 
727 	/* Finally copy the header into the image area */
728 	memcpy(ptr, image, headersz);
729 
730 	free(image);
731 }
732 
733 static void kwbimage_print_header(const void *ptr)
734 {
735 	struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
736 
737 	printf("Image Type:   MVEBU Boot from %s Image\n",
738 	       image_boot_mode_name(mhdr->blockid));
739 	printf("Image version:%d\n", image_version((void *)ptr));
740 	printf("Data Size:    ");
741 	genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
742 	printf("Load Address: %08x\n", mhdr->destaddr);
743 	printf("Entry Point:  %08x\n", mhdr->execaddr);
744 }
745 
746 static int kwbimage_check_image_types(uint8_t type)
747 {
748 	if (type == IH_TYPE_KWBIMAGE)
749 		return EXIT_SUCCESS;
750 	else
751 		return EXIT_FAILURE;
752 }
753 
754 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
755 				  struct image_tool_params *params)
756 {
757 	struct main_hdr_v0 *main_hdr;
758 	struct ext_hdr_v0 *ext_hdr;
759 	uint8_t checksum;
760 
761 	main_hdr = (void *)ptr;
762 	checksum = image_checksum8(ptr,
763 				   sizeof(struct main_hdr_v0)
764 				   - sizeof(uint8_t));
765 	if (checksum != main_hdr->checksum)
766 		return -FDT_ERR_BADSTRUCTURE;
767 
768 	/* Only version 0 extended header has checksum */
769 	if (image_version((void *)ptr) == 0) {
770 		ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
771 		checksum = image_checksum8(ext_hdr,
772 					   sizeof(struct ext_hdr_v0)
773 					   - sizeof(uint8_t));
774 		if (checksum != ext_hdr->checksum)
775 			return -FDT_ERR_BADSTRUCTURE;
776 	}
777 
778 	return 0;
779 }
780 
781 static int kwbimage_generate(struct image_tool_params *params,
782 			     struct image_type_params *tparams)
783 {
784 	int alloc_len;
785 	void *hdr;
786 	int version = 0;
787 
788 	version = image_version_file(params->imagename);
789 	if (version == 0) {
790 		alloc_len = sizeof(struct main_hdr_v0) +
791 			sizeof(struct ext_hdr_v0);
792 	} else {
793 		alloc_len = image_headersz_v1(params, NULL);
794 	}
795 
796 	hdr = malloc(alloc_len);
797 	if (!hdr) {
798 		fprintf(stderr, "%s: malloc return failure: %s\n",
799 			params->cmdname, strerror(errno));
800 		exit(EXIT_FAILURE);
801 	}
802 
803 	memset(hdr, 0, alloc_len);
804 	tparams->header_size = alloc_len;
805 	tparams->hdr = hdr;
806 
807 	return 0;
808 }
809 
810 /*
811  * Report Error if xflag is set in addition to default
812  */
813 static int kwbimage_check_params(struct image_tool_params *params)
814 {
815 	if (!strlen(params->imagename)) {
816 		fprintf(stderr, "Error:%s - Configuration file not specified, "
817 			"it is needed for kwbimage generation\n",
818 			params->cmdname);
819 		return CFG_INVALID;
820 	}
821 
822 	return (params->dflag && (params->fflag || params->lflag)) ||
823 		(params->fflag && (params->dflag || params->lflag)) ||
824 		(params->lflag && (params->dflag || params->fflag)) ||
825 		(params->xflag) || !(strlen(params->imagename));
826 }
827 
828 /*
829  * kwbimage type parameters definition
830  */
831 U_BOOT_IMAGE_TYPE(
832 	kwbimage,
833 	"Marvell MVEBU Boot Image support",
834 	0,
835 	NULL,
836 	kwbimage_check_params,
837 	kwbimage_verify_header,
838 	kwbimage_print_header,
839 	kwbimage_set_header,
840 	NULL,
841 	kwbimage_check_image_types,
842 	NULL,
843 	kwbimage_generate
844 );
845