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