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