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