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