xref: /openbmc/u-boot/tools/kwbimage.c (revision 3d3f60cb)
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 	version = image_get_version();
685 	switch (version) {
686 		/*
687 		 * Fallback to version 0 if no version is provided in the
688 		 * cfg file
689 		 */
690 	case -1:
691 	case 0:
692 		image = image_create_v0(&headersz, params, sbuf->st_size);
693 		break;
694 
695 	case 1:
696 		image = image_create_v1(&headersz, params, sbuf->st_size);
697 		break;
698 
699 	default:
700 		fprintf(stderr, "Unsupported version %d\n", version);
701 		free(image_cfg);
702 		exit(EXIT_FAILURE);
703 	}
704 
705 	if (!image) {
706 		fprintf(stderr, "Could not create image\n");
707 		free(image_cfg);
708 		exit(EXIT_FAILURE);
709 	}
710 
711 	free(image_cfg);
712 
713 	/* Build and add image checksum header */
714 	checksum = image_checksum32((uint32_t *)ptr, sbuf->st_size);
715 	size = write(ifd, &checksum, sizeof(uint32_t));
716 	if (size != sizeof(uint32_t)) {
717 		fprintf(stderr, "Error:%s - Checksum write %d bytes %s\n",
718 			params->cmdname, size, params->imagefile);
719 		exit(EXIT_FAILURE);
720 	}
721 
722 	sbuf->st_size += sizeof(uint32_t);
723 
724 	/* Finally copy the header into the image area */
725 	memcpy(ptr, image, headersz);
726 
727 	free(image);
728 }
729 
730 static void kwbimage_print_header(const void *ptr)
731 {
732 	struct main_hdr_v0 *mhdr = (struct main_hdr_v0 *)ptr;
733 
734 	printf("Image Type:   MVEBU Boot from %s Image\n",
735 	       image_boot_mode_name(mhdr->blockid));
736 	printf("Image version:%d\n", image_version((void *)ptr));
737 	printf("Data Size:    ");
738 	genimg_print_size(mhdr->blocksize - sizeof(uint32_t));
739 	printf("Load Address: %08x\n", mhdr->destaddr);
740 	printf("Entry Point:  %08x\n", mhdr->execaddr);
741 }
742 
743 static int kwbimage_check_image_types(uint8_t type)
744 {
745 	if (type == IH_TYPE_KWBIMAGE)
746 		return EXIT_SUCCESS;
747 	else
748 		return EXIT_FAILURE;
749 }
750 
751 static int kwbimage_verify_header(unsigned char *ptr, int image_size,
752 				  struct image_tool_params *params)
753 {
754 	struct main_hdr_v0 *main_hdr;
755 	struct ext_hdr_v0 *ext_hdr;
756 	uint8_t checksum;
757 
758 	main_hdr = (void *)ptr;
759 	checksum = image_checksum8(ptr,
760 				   sizeof(struct main_hdr_v0)
761 				   - sizeof(uint8_t));
762 	if (checksum != main_hdr->checksum)
763 		return -FDT_ERR_BADSTRUCTURE;
764 
765 	/* Only version 0 extended header has checksum */
766 	if (image_version((void *)ptr) == 0) {
767 		ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0);
768 		checksum = image_checksum8(ext_hdr,
769 					   sizeof(struct ext_hdr_v0)
770 					   - sizeof(uint8_t));
771 		if (checksum != ext_hdr->checksum)
772 			return -FDT_ERR_BADSTRUCTURE;
773 	}
774 
775 	return 0;
776 }
777 
778 static int kwbimage_generate(struct image_tool_params *params,
779 			     struct image_type_params *tparams)
780 {
781 	int alloc_len;
782 	void *hdr;
783 	int version = 0;
784 
785 	version = image_version_file(params->imagename);
786 	if (version == 0) {
787 		alloc_len = sizeof(struct main_hdr_v0) +
788 			sizeof(struct ext_hdr_v0);
789 	} else {
790 		alloc_len = image_headersz_v1(params, NULL);
791 	}
792 
793 	hdr = malloc(alloc_len);
794 	if (!hdr) {
795 		fprintf(stderr, "%s: malloc return failure: %s\n",
796 			params->cmdname, strerror(errno));
797 		exit(EXIT_FAILURE);
798 	}
799 
800 	memset(hdr, 0, alloc_len);
801 	tparams->header_size = alloc_len;
802 	tparams->hdr = hdr;
803 
804 	return 0;
805 }
806 
807 /*
808  * Report Error if xflag is set in addition to default
809  */
810 static int kwbimage_check_params(struct image_tool_params *params)
811 {
812 	if (!strlen(params->imagename)) {
813 		fprintf(stderr, "Error:%s - Configuration file not specified, "
814 			"it is needed for kwbimage generation\n",
815 			params->cmdname);
816 		return CFG_INVALID;
817 	}
818 
819 	return (params->dflag && (params->fflag || params->lflag)) ||
820 		(params->fflag && (params->dflag || params->lflag)) ||
821 		(params->lflag && (params->dflag || params->fflag)) ||
822 		(params->xflag) || !(strlen(params->imagename));
823 }
824 
825 /*
826  * kwbimage type parameters definition
827  */
828 U_BOOT_IMAGE_TYPE(
829 	kwbimage,
830 	"Marvell MVEBU Boot Image support",
831 	0,
832 	NULL,
833 	kwbimage_check_params,
834 	kwbimage_verify_header,
835 	kwbimage_print_header,
836 	kwbimage_set_header,
837 	NULL,
838 	kwbimage_check_image_types,
839 	NULL,
840 	kwbimage_generate
841 );
842