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