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