xref: /aosp_15_r20/external/coreboot/util/marvell/doimage_mv/doimage.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /*******************************************************************************
2 Copyright (C) Marvell International Ltd. and its affiliates
3 
4 Marvell GPL License Option
5 
6 If you received this File from Marvell, you may opt to use, redistribute and/or
7 modify this File in accordance with the terms and conditions of the General
8 Public License Version 2, June 1991 (the "GPL License"), a copy of which is
9 available along with the File in the license.txt file or by writing to the Free
10 Software Foundation, Inc.
11 
12 THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE IMPLIED
13 WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ARE EXPRESSLY
14 DISCLAIMED.  The GPL License provides additional details about this warranty
15 disclaimer.
16 
17 *******************************************************************************/
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <sys/mman.h>
26 #include <time.h>
27 #include <limits.h>
28 
29 #define _HOST_COMPILER
30 #include "bootstrap_def.h"
31 
32 #include "doimage.h"
33 
34 #undef DEBUG
35 
36 #ifdef DEBUG
37 #define DB(x...) fprintf(stdout, x)
38 #else
39 #define DB(x...)
40 #endif
41 
42 /* Global variables */
43 
44 int f_in = -1;
45 int f_out = -1;
46 int f_header = -1;
47 struct stat fs_stat;
48 
49 /*******************************************************************************
50 *    pre_load_image
51 *          pre-load the binary image into memory buffer taking into account
52 *paddings
53 *    INPUT:
54 *          opt        user options
55 *          buf_in     mmapped input file
56 *    OUTPUT:
57 *          none
58 *    RETURN:
59 *          0 on success
60 *******************************************************************************/
pre_load_image(USER_OPTIONS * opt,char * buf_in)61 int pre_load_image(USER_OPTIONS *opt, char *buf_in)
62 {
63 	int offset = 0;
64 
65 	opt->image_buf = malloc(opt->image_sz);
66 	if (opt->image_buf == NULL)
67 		return -1;
68 
69 	memset(opt->image_buf, 0, opt->image_sz);
70 
71 	if ((opt->pre_padding) && (opt->prepadding_size)) {
72 		memset(opt->image_buf, 0x5, opt->prepadding_size);
73 		offset = opt->prepadding_size;
74 	}
75 
76 	if ((opt->post_padding) && (opt->postpadding_size))
77 		memset(opt->image_buf + opt->image_sz - 4 -
78 			   opt->postpadding_size,
79 		       0xA, opt->postpadding_size);
80 
81 	memcpy(opt->image_buf + offset, buf_in, fs_stat.st_size);
82 
83 	return 0;
84 } /* end of pre_load_image() */
85 
86 /*******************************************************************************
87 *    build_twsi_header
88 *          create TWSI header and write it into output stream
89 *    INPUT:
90 *          opt        user options
91 *    OUTPUT:
92 *          none
93 *    RETURN:
94 *          0 on success
95 *******************************************************************************/
build_twsi_header(USER_OPTIONS * opt)96 int build_twsi_header(USER_OPTIONS *opt)
97 {
98 	FILE *f_twsi;
99 	MV_U8 *tmpTwsi = NULL;
100 	MV_U32 *twsi_reg;
101 	int i;
102 	MV_U32 twsi_size = 0;
103 
104 	tmpTwsi = malloc(MAX_TWSI_HDR_SIZE);
105 	if (tmpTwsi == NULL) {
106 		fprintf(stderr, "TWSI space allocation error!\n");
107 		return -1;
108 	}
109 	memset(tmpTwsi, 0xFF, MAX_TWSI_HDR_SIZE);
110 	twsi_reg = (MV_U32 *)tmpTwsi;
111 
112 	f_twsi = fopen(opt->fname_twsi, "r");
113 	if (f_twsi == NULL) {
114 		fprintf(stderr, "Failed to open file '%s'\n", opt->fname_twsi);
115 		perror("Error:");
116 		return -1;
117 	}
118 
119 	for (i = 0; i < (MAX_TWSI_HDR_SIZE / 4); i++) {
120 		if (EOF == fscanf(f_twsi, "%x\n", twsi_reg))
121 			break;
122 
123 		/* Swap Enianess */
124 		*twsi_reg =
125 		    (((*twsi_reg >> 24) & 0xFF) | ((*twsi_reg >> 8) & 0xFF00) |
126 		     ((*twsi_reg << 8) & 0xFF0000) |
127 		     ((*twsi_reg << 24) & 0xFF000000));
128 		twsi_reg++;
129 	}
130 
131 	fclose(f_twsi);
132 
133 	/* Align to size = 512,1024,.. with at least 8 0xFF bytes @ the end */
134 	twsi_size = ((((i + 2) * 4) & ~0x1FF) + 0x200);
135 
136 	if ((write(f_out, tmpTwsi, twsi_size)) != twsi_size) {
137 		fprintf(stderr, "Error writing %s file\n", opt->fname.out);
138 		return -1;
139 	}
140 
141 	return 0;
142 } /* end of build_twsi_header() */
143 
144 /*******************************************************************************
145 *    build_reg_header
146 *        create BIN header and write it into output stream
147 *    INPUT:
148 *       fname        - source file name
149 *       buffer       - Start address of boot image buffer
150 *       current_size - number of bytes already placed into the boot image buffer
151 *    OUTPUT:
152 *       none
153 *    RETURN:
154 *	size of a reg header or 0 on fail
155 *******************************************************************************/
build_reg_header(char * fname,MV_U8 * buffer,MV_U32 current_size)156 int build_reg_header(char *fname, MV_U8 *buffer, MV_U32 current_size)
157 {
158 	FILE *f_dram;
159 	BHR_t *mainHdr = (BHR_t *)buffer;
160 	headExtBHR_t *headExtHdr = headExtHdr =
161 	    (headExtBHR_t *)(buffer + current_size);
162 	tailExtBHR_t *prevExtHdrTail =
163 	    NULL; /* tail of the previous extension header */
164 	MV_U32 max_bytes_to_write;
165 	MV_U32 *dram_reg =
166 	    (MV_U32 *)(buffer + current_size + sizeof(headExtBHR_t));
167 	MV_U32 tmp_len;
168 	int i;
169 
170 	if (mainHdr->ext == 255) {
171 		fprintf(stderr, "Maximum number of extensions reached!\n");
172 		return 0;
173 	}
174 
175 	/* Indicate next header in previous extension if any */
176 	if (mainHdr->ext != 0) {
177 		prevExtHdrTail = (tailExtBHR_t *)(buffer + current_size -
178 						  sizeof(tailExtBHR_t));
179 		prevExtHdrTail->nextHdr = 1;
180 	}
181 
182 	/* Count extension headers in the main header */
183 	mainHdr->ext++;
184 
185 	headExtHdr->type = EXT_HDR_TYP_REGISTER;
186 	max_bytes_to_write = MAX_HEADER_SIZE - current_size - EXT_HDR_BASE_SIZE;
187 	f_dram = fopen(fname, "r");
188 	if (f_dram  == NULL) {
189 		fprintf(stderr, "Failed to open file '%s'\n", fname);
190 		perror("Error:");
191 		return 0;
192 	}
193 
194 	for (i = 0; i < (max_bytes_to_write / 8); i += 2) {
195 		if (fscanf(f_dram, "%x %x\n", &dram_reg[i], &dram_reg[i + 1]) ==
196 		    EOF)
197 			break;
198 		else if ((dram_reg[i] == 0x0) && (dram_reg[i + 1] == 0x0))
199 			break;
200 	}
201 
202 	fclose(f_dram);
203 
204 	if (i >= (max_bytes_to_write / 8)) {
205 		fprintf(stderr, "Registers configure exceeds maximum size\n");
206 		return 0;
207 	}
208 
209 	/* Include extended header head and tail sizes */
210 	tmp_len = EXT_HDR_BASE_SIZE + i * 4;
211 	/* Write total length into the current header fields */
212 	EXT_HDR_SET_LEN(headExtHdr, tmp_len);
213 
214 	return tmp_len;
215 } /* end of build_reg_header() */
216 
217 /*******************************************************************************
218 *    build_bin_header
219 *        create BIN header and write it into putput stream
220 *    INPUT:
221 *       fname        - source file name
222 *       buffer       - Start address of boot image buffer
223 *       current_size - number of bytes already placed into the boot image buffer
224 *    OUTPUT:
225 *       none
226 *    RETURN:
227 *	size of reg header
228 *******************************************************************************/
build_bin_header(char * fname,MV_U8 * buffer,MV_U32 current_size)229 int build_bin_header(char *fname, MV_U8 *buffer, MV_U32 current_size)
230 {
231 	FILE *f_bin;
232 	BHR_t *mainHdr = (BHR_t *)buffer;
233 	headExtBHR_t *headExtHdr = (headExtBHR_t *)(buffer + current_size);
234 	tailExtBHR_t *prevExtHdrTail =
235 	    NULL; /* tail of the previous extension header */
236 	MV_U32 max_bytes_to_write;
237 	MV_U32 *bin_reg =
238 	    (MV_U32 *)(buffer + current_size + sizeof(headExtBHR_t));
239 	MV_U32 tmp_len;
240 	int i;
241 
242 	if (mainHdr->ext == 255) {
243 		fprintf(stderr, "Maximum number of extensions reached!\n");
244 		return 0;
245 	}
246 
247 	/* Indicate next header in previous extension if any */
248 	if (mainHdr->ext != 0) {
249 		prevExtHdrTail = (tailExtBHR_t *)(buffer + current_size -
250 						  sizeof(tailExtBHR_t));
251 		prevExtHdrTail->nextHdr = 1;
252 	}
253 
254 	/* Count extension headers in main header */
255 	mainHdr->ext++;
256 
257 	headExtHdr->type = EXT_HDR_TYP_BINARY;
258 	max_bytes_to_write = MAX_HEADER_SIZE - current_size - EXT_HDR_BASE_SIZE;
259 
260 	f_bin = fopen(fname, "r");
261 	if (f_bin == NULL) {
262 		fprintf(stderr, "Failed to open file '%s'\n", fname);
263 		perror("Error:");
264 		return 0;
265 	}
266 
267 	for (i = 0; i < (max_bytes_to_write / 4); i++) {
268 		if (fread(bin_reg, 1, 4, f_bin) != 4)
269 			break;
270 
271 		bin_reg++;
272 	}
273 
274 	fclose(f_bin);
275 
276 	if (i >= (max_bytes_to_write / 4)) {
277 		fprintf(stderr, "Binary extension exeeds the maximum size\n");
278 		return 0;
279 	}
280 
281 	/* Include extended header head and tail sizes */
282 	tmp_len = EXT_HDR_BASE_SIZE + i * 4;
283 	/* Write total length into the current header fields */
284 	EXT_HDR_SET_LEN(headExtHdr, tmp_len);
285 
286 	return tmp_len;
287 } /* end of build_exec_header() */
288 
289 /*******************************************************************************
290 *    build_headers
291 *          build headers block based on user options and write it into output
292 *stream
293 *    INPUT:
294 *          opt        user options
295 *          buf_in     mmapped input file
296 *    OUTPUT:
297 *          none
298 *    RETURN:
299 *          0 on success
300 *******************************************************************************/
build_headers(USER_OPTIONS * opt,char * buf_in)301 int build_headers(USER_OPTIONS *opt, char *buf_in)
302 {
303 	BHR_t *hdr = NULL;
304 	secExtBHR_t *secExtHdr = NULL;
305 	headExtBHR_t *headExtHdr = NULL;
306 	tailExtBHR_t *tailExtHdr = NULL;
307 	MV_U8 *tmpHeader = NULL;
308 	int i;
309 	MV_U32 header_size = 0;
310 	int size_written = 0;
311 	MV_U32 max_bytes_to_write;
312 	int error = 1;
313 
314 	tmpHeader = malloc(MAX_HEADER_SIZE);
315 	if (tmpHeader == NULL) {
316 		fprintf(stderr, "Header space allocation error!\n");
317 		goto header_error;
318 	}
319 
320 	memset(tmpHeader, 0, MAX_HEADER_SIZE);
321 	hdr = (BHR_t *)tmpHeader;
322 
323 	switch (opt->image_type) {
324 	case IMG_SATA:
325 		hdr->blockID = IBR_HDR_SATA_ID;
326 		break;
327 
328 	case IMG_UART:
329 		hdr->blockID = IBR_HDR_UART_ID;
330 		break;
331 
332 	case IMG_FLASH:
333 		hdr->blockID = IBR_HDR_SPI_ID;
334 		break;
335 
336 	case IMG_MMC:
337 		hdr->blockID = IBR_HDR_MMC_ID;
338 		break;
339 
340 	case IMG_NAND:
341 		hdr->blockID = IBR_HDR_NAND_ID;
342 		/*hdr->nandEccMode = (MV_U8)opt->nandEccMode; <<== reserved */
343 		/*hdr->nandPageSize = (MV_U16)opt->nandPageSize; <<== reserved
344 		 */
345 		hdr->nandBlockSize = (MV_U8)opt->nandBlkSize;
346 		if ((opt->nandCellTech == 'S') || (opt->nandCellTech == 's'))
347 			hdr->nandTechnology = MAIN_HDR_NAND_SLC;
348 		else
349 			hdr->nandTechnology = MAIN_HDR_NAND_MLC;
350 		break;
351 
352 	case IMG_PEX:
353 		hdr->blockID = IBR_HDR_PEX_ID;
354 		break;
355 
356 	case IMG_I2C:
357 		hdr->blockID = IBR_HDR_I2C_ID;
358 		break;
359 
360 	default:
361 		fprintf(stderr,
362 			"Illegal image type %d for header construction!\n",
363 			opt->image_type);
364 		return 1;
365 	}
366 
367 	/* Debug print options */
368 	if (opt->flags & p_OPTION_MASK)
369 		hdr->flags &= ~BHR_FLAG_PRINT_EN;
370 	else
371 		hdr->flags |=
372 		    BHR_FLAG_PRINT_EN; /* Enable printing by default */
373 
374 	if (opt->flags & b_OPTION_MASK) {
375 		switch (opt->baudRate) {
376 		case 2400:
377 			hdr->options = BHR_OPT_BAUD_2400;
378 			break;
379 
380 		case 4800:
381 			hdr->options = BHR_OPT_BAUD_4800;
382 			break;
383 
384 		case 9600:
385 			hdr->options = BHR_OPT_BAUD_9600;
386 			break;
387 
388 		case 19200:
389 			hdr->options = BHR_OPT_BAUD_19200;
390 			break;
391 
392 		case 38400:
393 			hdr->options = BHR_OPT_BAUD_38400;
394 			break;
395 
396 		case 57600:
397 			hdr->options = BHR_OPT_BAUD_57600;
398 			break;
399 
400 		case 115200:
401 			hdr->options = BHR_OPT_BAUD_115200;
402 			break;
403 
404 		default:
405 			fprintf(stderr, "Unsupported baud rate - %d!\n",
406 				opt->baudRate);
407 			return 1;
408 		}
409 	} else
410 		hdr->options = BHR_OPT_BAUD_DEFAULT;
411 
412 	/* debug port number */
413 	if (opt->flags & u_OPTION_MASK)
414 		hdr->options |= (opt->debugPortNum << BHR_OPT_UART_PORT_OFFS) &
415 				BHR_OPT_UART_PORT_MASK;
416 
417 	/* debug port MPP setup index */
418 	if (opt->flags & m_OPTION_MASK)
419 		hdr->options |= (opt->debugPortMpp << BHR_OPT_UART_MPPS_OFFS) &
420 				BHR_OPT_UART_MPPS_MASK;
421 
422 	hdr->destinationAddr = opt->image_dest;
423 	hdr->executionAddr = (MV_U32)opt->image_exec;
424 	hdr->version = MAIN_HDR_VERSION;
425 	hdr->blockSize = fs_stat.st_size;
426 
427 	header_size = sizeof(BHR_t);
428 
429 	/* Update Block size address */
430 	if ((opt->flags & X_OPTION_MASK) || (opt->flags & Y_OPTION_MASK)) {
431 		/* Align padding to 32 bit */
432 		if (opt->prepadding_size & 0x3)
433 			opt->prepadding_size +=
434 			    (4 - (opt->prepadding_size & 0x3));
435 
436 		if (opt->postpadding_size & 0x3)
437 			opt->postpadding_size +=
438 			    (4 - (opt->postpadding_size & 0x3));
439 
440 		hdr->blockSize += opt->prepadding_size + opt->postpadding_size;
441 	}
442 
443 	/* Align the image size to 4 byte boundary */
444 	if (hdr->blockSize & 0x3) {
445 		opt->bytesToAlign = (4 - (hdr->blockSize & 0x3));
446 		hdr->blockSize += opt->bytesToAlign;
447 	}
448 
449 	/***************************** TWSI Header
450 	 * ********************************/
451 
452 	/* TWSI header has a special purpose and placed ahead of the main header
453 	 */
454 	if (opt->flags & M_OPTION_MASK) {
455 		if (opt->fname_twsi) {
456 			if (build_twsi_header(opt) != 0)
457 				goto header_error;
458 		} /* opt->fname_twsi */
459 	}	 /* (opt->flags & M_OPTION_MASK) */
460 
461 	/************************** End of TWSI Header
462 	 * ****************************/
463 
464 	/********************** Single Register Header
465 	 * ***************************/
466 
467 	if (opt->flags & R_OPTION_MASK) {
468 		if (opt->fname_dram) {
469 			MV_U32 rhdr_len = build_reg_header(
470 			    opt->fname_dram, tmpHeader, header_size);
471 			if (rhdr_len <= 0)
472 				goto header_error;
473 
474 			header_size += rhdr_len;
475 			tailExtHdr = (tailExtBHR_t *)(tmpHeader + header_size -
476 						      sizeof(tailExtBHR_t));
477 		} /* if (fname_dram) */
478 	}	 /* if (opts & R_OPTION_MASK) */
479 
480 	/******************** End of Single Register Header
481 	 * ************************/
482 
483 	/************************* Single Binary Header
484 	 * ****************************/
485 
486 	if (opt->flags & G_OPTION_MASK) {
487 		if (opt->fname_bin) {
488 			MV_U32 bhdr_len = build_bin_header(
489 			    opt->fname_bin, tmpHeader, header_size);
490 			if (bhdr_len <= 0)
491 				goto header_error;
492 
493 			header_size += bhdr_len;
494 			tailExtHdr = (tailExtBHR_t *)(tmpHeader + header_size -
495 						      sizeof(tailExtBHR_t));
496 		} /* if (fname_bin) */
497 	}	 /* (opt->flags & G_OPTION_MASK) */
498 
499 	/******************* End of Single Binary Header
500 	 * ***************************/
501 
502 	/************************* BIN/REG Headers list
503 	 * ****************************/
504 
505 	if (opt->flags & C_OPTION_MASK) {
506 		if (opt->fname_list) {
507 			FILE *f_list;
508 			char buffer[PATH_MAX + 5];
509 			char *fname;
510 			MV_U32 hdr_len = 0, last;
511 			int (*build_hdr_func)(char *, MV_U8 *, MV_U32);
512 
513 			f_list = fopen(opt->fname_list, "r");
514 			if (f_list == NULL) {
515 				fprintf(stderr, "File not found\n");
516 				goto header_error;
517 			}
518 			/* read the headers list row by row */
519 			while (fgets(buffer, PATH_MAX + 4, f_list) != NULL) {
520 				/* Ignore strings that are not starting with
521 				 * BIN/REG */
522 				if (strncmp(buffer, "BIN", 3) == 0)
523 					build_hdr_func = build_bin_header;
524 				else if (strncmp(buffer, "REG", 3) == 0)
525 					build_hdr_func = build_reg_header;
526 				else
527 					continue;
528 
529 				fname = buffer + 3;
530 				/* strip leading spaces/tabs if any */
531 				while ((strncmp(fname, " ", 1) == 0) ||
532 				       (strncmp(fname, "\t", 1) == 0))
533 					fname++;
534 
535 				/* strip trailing LF/CR symbols */
536 				last = strlen(fname) - 1;
537 				while ((strncmp(fname + last, "\n", 1) == 0) ||
538 				       (strncmp(fname + last, "\r", 1) == 0)) {
539 					fname[last] = 0;
540 					last--;
541 				}
542 				/* Insert required header into the output buffer
543 				 */
544 				hdr_len = build_hdr_func(fname, tmpHeader,
545 							 header_size);
546 				if (hdr_len <= 0)
547 					goto header_error;
548 
549 				header_size += hdr_len;
550 				tailExtHdr =
551 				    (tailExtBHR_t *)(tmpHeader + header_size -
552 						     sizeof(tailExtBHR_t));
553 			}
554 
555 			fclose(f_list);
556 		} /* if (fname_list) */
557 	}	 /* (opt->flags & C_OPTION_MASK) */
558 
559 	/********************** End of BIN/REG Headers list
560 	 * ************************/
561 
562 	/* Align the headers block to... */
563 	if (opt->image_type == IMG_NAND) {
564 		/* ... NAND page size */
565 		header_size +=
566 		    opt->nandPageSize - (header_size & (opt->nandPageSize - 1));
567 	} else if ((opt->image_type == IMG_SATA) ||
568 		   (opt->image_type == IMG_MMC)) {
569 		/* ... disk logical block size */
570 		header_size += 512 - (header_size & 0x1FF);
571 	} else if (opt->image_type == IMG_UART) {
572 		/* ... Xmodem packet size */
573 		header_size += 128 - (header_size & 0x7F);
574 	}
575 	/* Setup the image source address */
576 	if (opt->image_type == IMG_SATA) {
577 		if ((opt->image_source) && (opt->image_source > header_size))
578 			hdr->sourceAddr = opt->image_source;
579 		else
580 			hdr->sourceAddr =
581 			    header_size >> 9; /* Already aligned to 512 */
582 	} else {
583 		if ((opt->image_source) && (opt->image_source > header_size)) {
584 			hdr->sourceAddr = opt->image_source;
585 			opt->img_gap = opt->image_source - header_size;
586 		} else {
587 			/* The source imgage address should be aligned
588 			   to 32 byte boundary (cache line size).
589 			   For NAND it should be aligned to 512 bytes boundary
590 			   (for ECC)
591 			   The image immediately follows the header block,
592 			   so if the source address is undefined, it should be
593 			   derived from the header size.
594 			   The headers size is always  alighed to 4 byte
595 			   boundary */
596 			int boundary = 32;
597 
598 			if ((opt->image_type == IMG_NAND) ||
599 			    (opt->image_type == IMG_MMC))
600 				boundary = 512;
601 
602 			if (header_size & (boundary - 1))
603 				opt->img_gap =
604 				    boundary - (header_size & (boundary - 1));
605 
606 			hdr->sourceAddr = header_size + opt->img_gap;
607 		}
608 	}
609 
610 	/* source address and extension headers number can be written now */
611 	fprintf(stdout,
612 		"Ext. headers = %d, Header size = %d bytes Hdr-to-Img gap = %d bytes\n",
613 		hdr->ext, header_size, opt->img_gap);
614 
615 	/* If not UART/TWSI image, an extra word for boot image checksum is
616 	 * needed */
617 	if ((opt->image_type == IMG_FLASH) || (opt->image_type == IMG_NAND) ||
618 	    (opt->image_type == IMG_MMC) || (opt->image_type == IMG_SATA) ||
619 	    (opt->image_type == IMG_PEX) || (opt->image_type == IMG_I2C))
620 		hdr->blockSize += 4;
621 
622 	fprintf(stdout,
623 		"New image size = %#x[%d] Source image size = %#x[%d]\n",
624 		hdr->blockSize, hdr->blockSize, (unsigned int)fs_stat.st_size,
625 		(int)fs_stat.st_size);
626 
627 	hdr->hdrSizeMsb = (header_size & 0x00FF0000) >> 16;
628 	hdr->hdrSizeLsb = header_size & 0x0000FFFF;
629 
630 	opt->image_sz = hdr->blockSize;
631 
632 	/* Load image into memory buffer */
633 	if (REGULAR_IMAGE(opt)) {
634 		if (0 != pre_load_image(opt, buf_in)) {
635 			fprintf(stderr, "Failed image pre-load!\n");
636 			goto header_error;
637 		}
638 	}
639 
640 	/* Now the headers block checksum should be calculated and wrote in the
641 	 * header */
642 	/* This checksum value should be valid for both secure and unsecure boot
643 	 * modes */
644 	/* This value will be checked first before RSA key and signature
645 	 * verification */
646 	hdr->checkSum = checksum8((void *)hdr, MAIN_HDR_GET_LEN(hdr), 0);
647 
648 	/* Write to file(s) */
649 	if (opt->header_mode == HDR_IMG_TWO_FILES) {
650 		/* copy header to output image */
651 		size_written = write(f_header, tmpHeader, header_size);
652 		if (size_written != header_size) {
653 			fprintf(stderr, "Error writing %s file\n"
654 						, opt->fname.hdr_out);
655 			goto header_error;
656 		}
657 
658 		fprintf(stdout, "====>>>> %s was created\n",
659 			opt->fname_arr[HDR_FILE_INDX]);
660 		/* if (header_mode == HDR_IMG_TWO_FILES) */
661 	} else {
662 		/* copy header to output image */
663 		size_written = write(f_out, tmpHeader, header_size);
664 		if (size_written != header_size) {
665 			fprintf(stderr, "Error writing %s file\n"
666 						, opt->fname.out);
667 			goto header_error;
668 		}
669 
670 	} /* if (header_mode != HDR_IMG_TWO_FILES) */
671 
672 	error = 0;
673 
674 header_error:
675 
676 	if (tmpHeader)
677 		free(tmpHeader);
678 
679 	return error;
680 
681 } /* end of build_headers() */
682 
683 /*******************************************************************************
684 *    build_bootrom_img
685 *          create image in bootrom format and write it into output stream
686 *    INPUT:
687 *          opt        user options
688 *          buf_in     mmapped input file
689 *    OUTPUT:
690 *          none
691 *    RETURN:
692 *          0 on success
693 *******************************************************************************/
build_bootrom_img(USER_OPTIONS * opt,char * buf_in)694 int build_bootrom_img(USER_OPTIONS *opt, char *buf_in)
695 {
696 	unsigned int CRC_32 = 0;
697 	int tmpSize = BOOTROM_SIZE - sizeof(CRC_32);
698 	char *tmpImg = NULL;
699 	int size_written = 0;
700 	int error = 1;
701 
702 	tmpImg = malloc(tmpSize);
703 	if (tmpImg == NULL)
704 		return 1;
705 
706 	/* PAD image with Zeros until BOOTROM_SIZE*/
707 	memcpy(tmpImg, buf_in, fs_stat.st_size);
708 	memset(tmpImg + fs_stat.st_size, 0, tmpSize - fs_stat.st_size);
709 
710 	/* copy input image to output image */
711 	size_written = write(f_out, tmpImg, tmpSize);
712 
713 	/* calculate checsum */
714 	CRC_32 = crc32(0, (u32 *)tmpImg, tmpSize / 4);
715 	tmpSize += sizeof(CRC_32);
716 	printf("Image CRC32 (size = %d) = 0x%08x\n", tmpSize, CRC_32);
717 
718 	size_written += write(f_out, &CRC_32, sizeof(CRC_32));
719 
720 	if (size_written == tmpSize)
721 		error = 0;
722 
723 bootrom_img_error:
724 
725 	if (tmpImg)
726 		free(tmpImg);
727 
728 	return error;
729 } /* end of build_bootrom_img() */
730 
731 /*******************************************************************************
732 *    build_hex_img
733 *          create image in hex format and write it into output stream
734 *    INPUT:
735 *          opt        user options
736 *          buf_in     mmapped input file
737 *    OUTPUT:
738 *          none
739 *    RETURN:
740 *          0 on success
741 *******************************************************************************/
build_hex_img(USER_OPTIONS * opt,char * buf_in)742 int build_hex_img(USER_OPTIONS *opt, char *buf_in)
743 {
744 	FILE *f_desc[2] = {NULL};
745 	char *tmpImg = NULL;
746 	int hex_len;
747 	int hex_unaligned_len = 0;
748 	unsigned char *hex8 = NULL;
749 	unsigned char tmp8;
750 	unsigned short *hex16 = NULL;
751 	unsigned short tmp16;
752 	unsigned int *hex32 = NULL;
753 	unsigned int tmp32;
754 	unsigned int tmp32_low;
755 	int size_written = 0;
756 	int alignment = 0;
757 	int files_num;
758 	int i;
759 	int error = 1;
760 
761 	/* Calculate aligned image size */
762 	hex_len = fs_stat.st_size;
763 
764 	alignment = opt->hex_width >> 3;
765 	hex_unaligned_len = fs_stat.st_size & (alignment - 1);
766 
767 	if (hex_unaligned_len) {
768 		hex_len -= hex_unaligned_len;
769 		hex_len += alignment;
770 	}
771 
772 	/* Copy the input image to memory buffer */
773 	tmpImg = malloc(hex_len);
774 	if (tmpImg == NULL)
775 		goto hex_image_end;
776 
777 	memset(tmpImg, 0, hex_len);
778 	memcpy(tmpImg, buf_in, fs_stat.st_size);
779 
780 	if (opt->fname.hdr_out)
781 		files_num = 2;
782 	else
783 		files_num = 1;
784 
785 	for (i = 0; i < files_num; i++) {
786 		f_desc[i] = fopen(opt->fname_arr[i + 1], "w");
787 		if (f_desc[i] == NULL)
788 			goto hex_image_end;
789 	}
790 
791 	switch (opt->hex_width) {
792 	case 8:
793 		hex8 = (unsigned char *)tmpImg;
794 
795 		for (i = 0; hex_len > 0; hex_len--) {
796 			fprintf(f_desc[i], "%02X\n", *hex8++);
797 			size_written += 1;
798 			i ^= files_num - 1;
799 		}
800 		break;
801 
802 	case 16:
803 		hex16 = (unsigned short *)tmpImg;
804 
805 		for (; hex_len > 0; hex_len -= 2) {
806 			fprintf(f_desc[0], "%04X\n", *hex16++);
807 			size_written += 2;
808 		}
809 		break;
810 
811 	case 32:
812 		hex32 = (unsigned int *)tmpImg;
813 
814 		for (; hex_len > 0; hex_len -= 4) {
815 			fprintf(f_desc[0], "%08X\n", *hex32++);
816 			size_written += 4;
817 		}
818 		break;
819 
820 	case 64:
821 		hex32 = (unsigned int *)tmpImg;
822 
823 		for (; hex_len > 0; hex_len -= 8) {
824 			fprintf(f_desc[0], "%08X%08X\n", *hex32++, *hex32++);
825 			size_written += 8;
826 		}
827 		break;
828 
829 	} /* switch (opt->hex_width)*/
830 
831 	error = 0;
832 
833 hex_image_end:
834 
835 	if (tmpImg)
836 		free(tmpImg);
837 
838 	for (i = 0; i < files_num; i++) {
839 		if (f_desc[i] != NULL)
840 			fclose(f_desc[i]);
841 	}
842 
843 	return error;
844 } /* end of build_hex_img() */
845 
846 /*******************************************************************************
847 *    build_bin_img
848 *          create image in binary format and write it into output stream
849 *    INPUT:
850 *          opt        user options
851 *          buf_in     mmapped input file
852 *    OUTPUT:
853 *          none
854 *    RETURN:
855 *          0 on success
856 *******************************************************************************/
build_bin_img(USER_OPTIONS * opt,char * buf_in)857 int build_bin_img(USER_OPTIONS *opt, char *buf_in)
858 {
859 	FILE *f_ds = NULL;
860 	FILE *f_desc[4] = {NULL};
861 	char *tmpImg = NULL;
862 	int hex_len = 0;
863 	int one_file_len = 0;
864 	int size_written = 0;
865 	int alignment = 0;
866 	int hex_unaligned_len = 0;
867 	unsigned char *hex8 = NULL;
868 	unsigned char tmp8;
869 	unsigned short *hex16 = NULL;
870 	unsigned short tmp16;
871 	unsigned long *hex32 = NULL;
872 	unsigned long tmp32;
873 	unsigned long tmp32low;
874 	int i;
875 	int fidx;
876 	int files_num = 1;
877 	int error = 1;
878 
879 	/* Calculate aligned image size */
880 	hex_len = fs_stat.st_size;
881 
882 	alignment = opt->hex_width >> 3;
883 	hex_unaligned_len = fs_stat.st_size & (alignment - 1);
884 
885 	if (hex_unaligned_len) {
886 		hex_len -= hex_unaligned_len;
887 		hex_len += alignment;
888 	}
889 
890 	/* prepare output files */
891 	if (opt->fname.romd) /*16KB*/
892 		files_num = 4;
893 	else if (opt->fname.romc) /*12KB*/
894 		files_num = 3;
895 	else if (opt->fname.hdr_out)
896 		files_num = 2;
897 
898 	one_file_len = hex_len / files_num;
899 
900 	for (i = 0; i < files_num; i++) {
901 		f_desc[i] = fopen(opt->fname_arr[i + 1], "w");
902 		if (f_desc[i] == NULL)
903 			goto bin_image_end;
904 	}
905 
906 	/* Copy the input image to memory buffer */
907 	tmpImg = malloc(hex_len);
908 	if (tmpImg == NULL)
909 		goto bin_image_end;
910 
911 	memset(tmpImg, 0, (hex_len));
912 	memcpy(tmpImg, buf_in, fs_stat.st_size);
913 
914 	/* Split output image buffer according to width and number of files */
915 	switch (opt->hex_width) {
916 	case 8:
917 		hex8 = (unsigned char *)tmpImg;
918 		if (files_num != 2) {
919 			fprintf(stderr,
920 				"Must supply two output file names for this width!\n");
921 			goto bin_image_end;
922 		}
923 
924 		for (fidx = 1; (fidx >= 0) && (hex_len > 0); fidx--) {
925 			f_ds = f_desc[1 - fidx];
926 
927 			for (; hex_len > (fidx * one_file_len); hex_len--) {
928 				tmp8 = *hex8;
929 
930 				for (i = 0; i < opt->hex_width; i++) {
931 					fprintf(f_ds, "%d",
932 						((tmp8 & 0x80) >> 7));
933 					tmp8 <<= 1;
934 				}
935 				fprintf(f_ds, "\n");
936 
937 				hex8++;
938 				size_written += 1;
939 			}
940 		}
941 		break;
942 
943 	case 16:
944 		hex16 = (unsigned short *)tmpImg;
945 
946 		for (; hex_len > 0; hex_len -= 2) {
947 			tmp16 = *hex16;
948 
949 			for (i = 0; i < opt->hex_width; i++) {
950 				fprintf(f_desc[0], "%d",
951 					((tmp16 & 0x8000) >> 15));
952 				tmp16 <<= 1;
953 			}
954 			fprintf(f_desc[0], "\n");
955 
956 			hex16++;
957 			size_written += 2;
958 		}
959 		break;
960 
961 	case 32:
962 		hex32 = (long *)tmpImg;
963 
964 		for (fidx = files_num - 1; (fidx >= 0) && (hex_len > 0);
965 		     fidx--) {
966 			f_ds = f_desc[files_num - 1 - fidx];
967 
968 			for (; hex_len > (fidx * one_file_len); hex_len -= 4) {
969 				tmp32 = *hex32;
970 
971 				for (i = 0; i < opt->hex_width; i++) {
972 					fprintf(f_ds, "%ld",
973 						((tmp32 & 0x80000000) >> 31));
974 					tmp32 <<= 1;
975 				}
976 				fprintf(f_ds, "\n");
977 				hex32++;
978 				size_written += 4;
979 			}
980 		}
981 		break;
982 
983 	case 64:
984 		hex32 = (long *)tmpImg;
985 
986 		for (; hex_len > 0; hex_len -= 8) {
987 			tmp32low = *hex32++;
988 			tmp32 = *hex32++;
989 
990 			for (i = 0; i < 32; i++) {
991 				fprintf(f_desc[0], "%ld",
992 					((tmp32 & 0x80000000) >> 31));
993 				tmp32 <<= 1;
994 			}
995 			for (i = 0; i < 32; i++) {
996 				fprintf(f_desc[0], "%ld",
997 					((tmp32low & 0x80000000) >> 31));
998 				tmp32low <<= 1;
999 			}
1000 			fprintf(f_desc[0], "\n");
1001 			size_written += 8;
1002 		}
1003 		break;
1004 	} /* switch (opt->hex_width) */
1005 
1006 	error = 0;
1007 
1008 bin_image_end:
1009 
1010 	if (tmpImg)
1011 		free(tmpImg);
1012 
1013 	for (i = 0; i < files_num; i++) {
1014 		if (f_desc[i] != NULL)
1015 			fclose(f_desc[i]);
1016 	}
1017 
1018 	return error;
1019 
1020 } /*  end of build_bin_img() */
1021 
1022 /*******************************************************************************
1023 *    build_regular_img
1024 *          create regular boot image and write it into output stream
1025 *    INPUT:
1026 *          opt        user options
1027 *          buf_in     mmapped input file
1028 *    OUTPUT:
1029 *          none
1030 *    RETURN:
1031 *          0 on success
1032 *******************************************************************************/
build_regular_img(USER_OPTIONS * opt,char * buf_in)1033 int build_regular_img(USER_OPTIONS *opt, char *buf_in)
1034 {
1035 	int size_written = 0;
1036 	int new_file_size = 0;
1037 	MV_U32 chsum32 = 0;
1038 
1039 	new_file_size = opt->image_sz;
1040 
1041 	if (0 != opt->img_gap) { /* cache line/NAND page/requested offset image
1042 				    alignment */
1043 		MV_U8 *gap_buf;
1044 
1045 		gap_buf = calloc(opt->img_gap, sizeof(MV_U8));
1046 		if (gap_buf == NULL) {
1047 			fprintf(stderr,
1048 				"Failed to allocate memory for header to image gap!\n");
1049 			return 1;
1050 		}
1051 		size_written += write(f_out, gap_buf, opt->img_gap);
1052 		new_file_size += opt->img_gap;
1053 		free(gap_buf);
1054 	}
1055 
1056 	/* Calculate checksum and copy it to the image tail */
1057 	chsum32 = checksum32((void *)opt->image_buf, opt->image_sz - 4, 0);
1058 	memcpy(opt->image_buf + opt->image_sz - 4, &chsum32, 4);
1059 
1060 	/* copy input image to output image */
1061 	size_written += write(f_out, opt->image_buf, opt->image_sz);
1062 	free(opt->image_buf);
1063 
1064 	if (new_file_size != size_written) {
1065 		fprintf(stderr, "Size mismatch between calculated/written\n");
1066 		return 1;
1067 	}
1068 
1069 	return 0;
1070 } /* end of build_other_img() */
1071 
1072 /*******************************************************************************
1073 *    process_image
1074 *          handle input and output file options, read and verify RSA and AES
1075 *keys.
1076 *    INPUT:
1077 *          opt        user options
1078 *    OUTPUT:
1079 *          none
1080 *    RETURN:
1081 *          0 on success
1082 ******************************************************************************/
process_image(USER_OPTIONS * opt)1083 int process_image(USER_OPTIONS *opt)
1084 {
1085 	int i;
1086 	int override[2];
1087 	char *buf_in = NULL;
1088 	int err = 1;
1089 
1090 	/* check if the output image exist */
1091 	printf(" ");
1092 	for (i = IMG_FILE_INDX; i <= HDR_FILE_INDX; i++) {
1093 		if (opt->fname_arr[i]) {
1094 			override[i] = 0;
1095 
1096 			if (0 == stat(opt->fname_arr[i], &fs_stat)) {
1097 				char c;
1098 				/* ask for overwrite permissions */
1099 				fprintf(stderr,
1100 					"File '%s' already exist! Overwrite it (Y/n)?",
1101 					opt->fname_arr[i]);
1102 				c = getc(stdin);
1103 				if ((c == 'N') || (c == 'n')) {
1104 					printf("exit.. nothing done.\n");
1105 					exit(0);
1106 				} else if ((c == 'Y') || (c == 'y')) {
1107 					/* additional read is needed for Enter
1108 					 * key */
1109 					c = getc(stdin);
1110 				}
1111 				override[i] = 1;
1112 			}
1113 		}
1114 	}
1115 
1116 	/* open input image file and check if it's size is OK */
1117 	if (opt->header_mode != HDR_ONLY) {
1118 		f_in = open(opt->fname.in, O_RDONLY | O_BINARY);
1119 		if (f_in == -1) {
1120 			fprintf(stderr, "File '%s' not found\n", opt->fname.in);
1121 			goto end;
1122 		}
1123 		/* get the size of the input image */
1124 		if (0 != fstat(f_in, &fs_stat)) {
1125 			fprintf(stderr, "fstat failed for file: '%s' err=%d\n",
1126 				opt->fname.in, err);
1127 			goto end;
1128 		}
1129 		/*Check the source image size for limited output storage
1130 		 * (bootrom) */
1131 		if (opt->image_type == IMG_BOOTROM) {
1132 			int max_img_size = BOOTROM_SIZE - sizeof(u32);
1133 
1134 			if (fs_stat.st_size > max_img_size) {
1135 				fprintf(stderr,
1136 					"ERROR : source image is bigger than %d bytes\n",
1137 					max_img_size);
1138 				goto end;
1139 			}
1140 		}
1141 		/* map the input image */
1142 		buf_in =
1143 		    mmap(0, fs_stat.st_size, PROT_READ, MAP_SHARED, f_in, 0);
1144 		if (!buf_in) {
1145 			fprintf(stderr, "Error mapping %s file\n",
1146 				opt->fname.in);
1147 			goto end;
1148 		}
1149 	}
1150 
1151 	/* open the output image file */
1152 	if (override[IMG_FILE_INDX] == 0)
1153 		f_out = open(opt->fname.out,
1154 			     O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0666);
1155 	else
1156 		f_out = open(opt->fname.out, O_RDWR | O_BINARY);
1157 
1158 	if (f_out == -1) {
1159 		fprintf(stderr, "Error opening %s file\n", opt->fname.out);
1160 		goto end;
1161 	}
1162 
1163 	/* open the output header file */
1164 	if (opt->header_mode == HDR_IMG_TWO_FILES) {
1165 		if (override[HDR_FILE_INDX] == 0)
1166 			f_header =
1167 			    open(opt->fname.hdr_out,
1168 				 O_RDWR | O_TRUNC | O_CREAT | O_BINARY, 0666);
1169 		else
1170 			f_header = open(opt->fname.hdr_out, O_RDWR | O_BINARY);
1171 
1172 		if (f_header == -1) {
1173 			fprintf(stderr, "Error opening %s file\n",
1174 				opt->fname.hdr_out);
1175 			goto end;
1176 		}
1177 	}
1178 
1179 	/* Image Header(s)  */
1180 	if (opt->header_mode != IMG_ONLY) {
1181 		if (0 != build_headers(opt, buf_in))
1182 			goto end;
1183 	}
1184 
1185 	/* Output Image  */
1186 	if (opt->header_mode != HDR_ONLY) {
1187 		if (opt->image_type == IMG_BOOTROM)
1188 			err = build_bootrom_img(opt, buf_in);
1189 		else if (opt->image_type == IMG_HEX)
1190 			err = build_hex_img(opt, buf_in);
1191 		else if (opt->image_type == IMG_BIN)
1192 			err = build_bin_img(opt, buf_in);
1193 		else
1194 			err = build_regular_img(opt, buf_in);
1195 
1196 		if (err != 0) {
1197 			fprintf(stderr, "Error writing %s file\n"
1198 						, opt->fname.out);
1199 			goto end;
1200 		}
1201 
1202 		fprintf(stdout, "====>>>> %s was created\n",
1203 			opt->fname_arr[IMG_FILE_INDX]);
1204 
1205 	} /* if (opt->header_mode != HDR_ONLY) */
1206 
1207 end:
1208 	/* close handles */
1209 	if (f_out != -1)
1210 		close(f_out);
1211 
1212 	if (f_header != -1)
1213 		close(f_header);
1214 
1215 	if (buf_in)
1216 		munmap((void *)buf_in, fs_stat.st_size);
1217 
1218 	if (f_in != -1)
1219 		close(f_in);
1220 
1221 	return err;
1222 
1223 } /* end of process_image() */
1224 
1225 /*******************************************************************************
1226 *    print_usage
1227 *          print command switches and their description
1228 *    INPUT:
1229 *          none
1230 *    OUTPUT:
1231 *          none
1232 *    RETURN:
1233 *          none
1234 *******************************************************************************/
print_usage(void)1235 void print_usage(void)
1236 {
1237 	printf(
1238 	    "==============================================================================================\n\n");
1239 	printf("Marvell doimage Tool version %s\n", VERSION_NUMBER);
1240 	printf("Supported SoC devices:\n\t%s\n", PRODUCT_SUPPORT);
1241 	printf(
1242 	    "==============================================================================================\n\n");
1243 	printf("Usage:\n");
1244 	printf(
1245 	    "doimage <mandatory_opt> [other_options] [bootrom_output] <image_in> <image_out> [header_out]\n\n");
1246 
1247 	printf("<mandatory_opt> - can be one or more of the following:\n");
1248 	printf(
1249 	    "==============================================================================================\n\n");
1250 
1251 	printf(
1252 	    "-T image_type:   sata\\uart\\flash\\bootrom\\nand\\hex\\bin\\pex\\mmc\n");
1253 	printf("-D image_dest:   image destination in dram (in hex)\n");
1254 	printf("-E image_exec:   execution address in dram (in hex)\n");
1255 	printf(
1256 	    "                 if image_type is 'flash' and image_dest is 0xffffffff\n");
1257 	printf("                 then execution address on the flash\n");
1258 	printf(
1259 	    "-S image_source: if image_type is sata then the starting sector of\n");
1260 	printf("                 the source image on the disk\n");
1261 	printf(
1262 	    "                 if image_type is flash\\nand then the starting offset of\n");
1263 	printf(
1264 	    "                 the source image at the flash - optional for flash\\nand\n");
1265 	printf("-W hex_width :   HEX file width, can be 8,16,32,64\n");
1266 	printf(
1267 	    "-M twsi_file:    ascii file name that contains the I2C init regs set by h/w.\n");
1268 	printf("                 this is used in i2c boot only\n");
1269 
1270 	printf("\nThe following options are mandatory for NAND image type:\n");
1271 	printf(
1272 	    "-----------------------------------------------------------------------------------------------\n\n");
1273 
1274 	printf(
1275 	    "-L nand_blk_size:NAND block size in KBytes (decimal int in range 64-16320)\n");
1276 	printf(
1277 	    "                 This parameter is ignored for flashes with  512B pages\n");
1278 	printf(
1279 	    "                 Such small page flashes always use 16K block sizes\n");
1280 	printf(
1281 	    "-N nand_cell_typ:NAND cell technology type (char: M for MLC, S for SLC)\n");
1282 	printf(
1283 	    "-P nand_pg_size: NAND page size: (decimal 512, 2048, 4096 or 8192)\n");
1284 
1285 	printf(
1286 	    "-G exec_file:    ascii file name that contains binary routine (ARM 5TE THUMB)\n");
1287 	printf(
1288 	    "                 to run before the bootloader image execution.\n");
1289 	printf(
1290 	    "                 The routine must contain an appropriate code for saving\n");
1291 	printf(
1292 	    "                 all registers at the routine start and restore them\n");
1293 	printf("                 before return from the routine\n");
1294 	printf(
1295 	    "-R dram_file:    ascii file name that contains the list of dram regs\n");
1296 	printf(
1297 	    "-C hdrs_file:    ascii file name that defines BIN/REG headers order and their sources\n");
1298 	printf("-X pre_padding_size (hex)\n");
1299 	printf("-Y post_padding_size (hex)\n");
1300 	printf("-H header_mode: Header mode, can be:\n");
1301 	printf(
1302 	    "                -H 1 : will create one file (image_out) for header and image\n");
1303 	printf(
1304 	    "                -H 2 : will create two files, (image_out) for image , (header_out) for header\n");
1305 	printf(
1306 	    "                -H 3 : will create one file (image_out) for header only\n");
1307 	printf(
1308 	    "                -H 4 : will create one file (image_out) for image only\n");
1309 
1310 	printf(
1311 	    "\n[bootrom_output] - optional and can be one or more of the following:\n");
1312 	printf(
1313 	    "==============================================================================================\n\n");
1314 
1315 	printf(
1316 	    "-p               Disable BootROM messages output to UART port (enabled by default)\n");
1317 	printf("-b baudrate      Set BootROM debug port UART baudrate\n");
1318 	printf(
1319 	    "                 value = 2400,4800,9600,19200,38400,57600,115200 (use default baudrate is omitted)\n");
1320 	printf(
1321 	    "-u port_num      Set BootROM debug port UART number value = 0-3 (use default port if omitted)\n");
1322 	printf(
1323 	    "-m mpp_config    Select BootROM debug port MPPs configuration value = 0-7 (BootROM-specific)\n");
1324 
1325 	printf("\nCommand examples:\n\n");
1326 
1327 	printf("doimage -T hex -W width image_in image_out\n");
1328 	printf("doimage -T bootrom image_in image_out\n");
1329 	printf("doimage -T resume image_in image_out\n");
1330 	printf("doimage -T sata -S sector -D image_dest -E image_exec\n");
1331 	printf("         [other_options] image_in image_out header_out\n\n");
1332 	printf("doimage -T flash -D image_dest -E image_exec [-S address]\n");
1333 	printf("         [other_options] image_in image_out\n\n");
1334 	printf("doimage -T pex -D image_dest -E image_exec\n");
1335 	printf("         [other_options] image_in image_out\n\n");
1336 	printf(
1337 	    "doimage -T nand -D image_dest -E image_exec [-S address] -P page_size\n");
1338 	printf("         -L 2 -N S [other_options] image_in image_out\n\n");
1339 	printf("doimage -T uart -D image_dest -E image_exec\n");
1340 	printf("         [other_options] image_in image_out\n\n");
1341 	printf("doimage -T pex -D image_dest -E image_exec\n");
1342 	printf("         [other_options] image_in image_out\n\n");
1343 	printf("\n\n");
1344 
1345 } /* end of print_usage() */
1346 
1347 /*******************************************************************************
1348 *    checksum8
1349 *          calculate 8-bit checksum of memory buffer
1350 *    INPUT:
1351 *          start        buffer start
1352 *          len          buffer length
1353 *          csum         initial checksum value
1354 *    OUTPUT:
1355 *          none
1356 *    RETURN:
1357 *          8-bit buffer checksum
1358 *******************************************************************************/
checksum8(void * start,MV_U32 len,MV_U8 csum)1359 MV_U8 checksum8(void *start, MV_U32 len, MV_U8 csum)
1360 {
1361 	register MV_U8 sum = csum;
1362 
1363 	volatile MV_U8 *startp = (volatile MV_U8 *)start;
1364 
1365 	do {
1366 		sum += *(MV_U8 *)startp;
1367 		startp++;
1368 
1369 	} while (--len);
1370 
1371 	return sum;
1372 
1373 } /* end of checksum8 */
1374 
1375 /*******************************************************************************
1376 *    checksum32
1377 *          calculate 32-bit checksum of memory buffer
1378 *    INPUT:
1379 *          start        buffer start
1380 *          len          buffer length
1381 *          csum         initial checksum value
1382 *    OUTPUT:
1383 *          none
1384 *    RETURN:
1385 *          32-bit buffer checksum
1386 *******************************************************************************/
checksum32(void * start,MV_U32 len,MV_U32 csum)1387 MV_U32 checksum32(void *start, MV_U32 len, MV_U32 csum)
1388 {
1389 	register MV_U32 sum = csum;
1390 	volatile MV_U32 *startp = (volatile MV_U32 *)start;
1391 
1392 	do {
1393 		sum += *(MV_U32 *)startp;
1394 		startp++;
1395 		len -= 4;
1396 
1397 	} while (len);
1398 
1399 	return sum;
1400 
1401 } /* *end of checksum32() */
1402 
1403 /*******************************************************************************
1404 *    make_crc_table
1405 *          init CRC table
1406 *    INPUT:
1407 *          crc_table   CRC table location
1408 *    OUTPUT:
1409 *          crc_table   CRC table location
1410 *    RETURN:
1411 *          none
1412 *******************************************************************************/
make_crc_table(MV_U32 * crc_table)1413 void make_crc_table(MV_U32 *crc_table)
1414 {
1415 	MV_U32 c;
1416 	MV_32 n, k;
1417 	MV_U32 poly;
1418 
1419 	/* terms of polynomial defining this crc (except x^32): */
1420 	static const MV_U8 p[] = {0,  1,  2,  4,  5,  7,  8,
1421 				  10, 11, 12, 16, 22, 23, 26};
1422 
1423 	/* make exclusive-or pattern from polynomial (0xedb88320L) */
1424 	poly = 0L;
1425 	for (n = 0; n < sizeof(p) / sizeof(MV_U8); n++)
1426 		poly |= 1L << (31 - p[n]);
1427 
1428 	for (n = 0; n < 256; n++) {
1429 		c = (MV_U32)n;
1430 		for (k = 0; k < 8; k++)
1431 			c = c & 1 ? poly ^ (c >> 1) : c >> 1;
1432 		crc_table[n] = c;
1433 	}
1434 
1435 } /* end of make_crc_table */
1436 
1437 #define DO1(buf) (crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8))
1438 #define DO2(buf) do {                                                 \
1439 	DO1(buf);                                                     \
1440 	DO1(buf);							\
1441 	} while (0)
1442 #define DO4(buf) do {                                                   \
1443 	DO2(buf);                                                       \
1444 	DO2(buf);							\
1445 	} while (0)
1446 #define DO8(buf) do {                                                   \
1447 	DO4(buf);                                                       \
1448 	DO4(buf);							\
1449 	} while (0)
1450 
1451 /*******************************************************************************
1452 *    crc32
1453 *          calculate CRC32 on memory buffer
1454 *    INPUT:
1455 *          crc       initial CRC value
1456 *          buf       memory buffer
1457 *          len       buffer length
1458 *    OUTPUT:
1459 *          none
1460 *    RETURN:
1461 *          CRC32 of the memory buffer
1462 *******************************************************************************/
crc32(MV_U32 crc,volatile MV_U32 * buf,MV_U32 len)1463 MV_U32 crc32(MV_U32 crc, volatile MV_U32 *buf, MV_U32 len)
1464 {
1465 	MV_U32 crc_table[256];
1466 
1467 	/* Create the CRC table */
1468 	make_crc_table(crc_table);
1469 
1470 	crc = crc ^ 0xffffffffL;
1471 	while (len >= 8) {
1472 		DO8(buf);
1473 		len -= 8;
1474 	}
1475 
1476 	if (len) {
1477 		do {
1478 			DO1(buf);
1479 		} while (--len);
1480 	}
1481 
1482 	return crc ^ 0xffffffffL;
1483 
1484 } /* end of crc32() */
1485 
1486 /*******************************************************************************
1487 *    select_image
1488 *          select image options by the image name
1489 *    INPUT:
1490 *          img_name       image name
1491 *    OUTPUT:
1492 *          opt            image options
1493 *    RETURN:
1494 *          0 on success, 1 if image name is invalid
1495 *******************************************************************************/
select_image(char * img_name,USER_OPTIONS * opt)1496 int select_image(char *img_name, USER_OPTIONS *opt)
1497 {
1498 	int i;
1499 
1500 	static IMG_MAP img_map[] = {
1501 	    {IMG_SATA, "sata", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK},
1502 	    {IMG_UART, "uart", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK},
1503 	    {IMG_FLASH, "flash", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK},
1504 	    {IMG_MMC, "mmc", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK},
1505 	    {IMG_BOOTROM, "bootrom", T_OPTION_MASK},
1506 	    {IMG_NAND, "nand", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK |
1507 				   L_OPTION_MASK | N_OPTION_MASK |
1508 				   P_OPTION_MASK},
1509 	    {IMG_HEX, "hex", T_OPTION_MASK | W_OPTION_MASK},
1510 	    {IMG_BIN, "bin", T_OPTION_MASK | W_OPTION_MASK},
1511 	    {IMG_PEX, "pex", D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK},
1512 	    {IMG_I2C, "i2c",
1513 	     D_OPTION_MASK | T_OPTION_MASK | E_OPTION_MASK | M_OPTION_MASK},
1514 	};
1515 
1516 	for (i = 0; i < ARRAY_SIZE(img_map); i++) {
1517 		if (strcmp(img_name, img_map[i].img_name) == 0) {
1518 			opt->image_type = img_map[i].img_type;
1519 			opt->req_flags = img_map[i].img_opt;
1520 			return 0;
1521 		}
1522 	}
1523 
1524 	return 1;
1525 
1526 } /* *end of select_image() */
1527 
1528 /*******************************************************************************
1529 *    main
1530 *******************************************************************************/
main(int argc,char ** argv)1531 int main(int argc, char **argv)
1532 {
1533 	USER_OPTIONS options;
1534 	int optch; /* command-line option char */
1535 	static char optstring[] =
1536 	    "T:D:E:X:Y:S:P:W:H:R:M:G:L:N:C:b:u:m:p";
1537 	int i, k;
1538 
1539 	if (argc < 2)
1540 		goto parse_error;
1541 
1542 	memset(&options, 0, sizeof(USER_OPTIONS));
1543 	options.header_mode = HDR_IMG_ONE_FILE;
1544 
1545 	fprintf(stdout, "\n");
1546 
1547 	while ((optch = getopt(argc, argv, optstring)) != -1) {
1548 		char *endptr = NULL;
1549 
1550 		switch (optch) {
1551 		case 'T': /* image type */
1552 			if ((select_image(optarg, &options) != 0) ||
1553 			    (options.flags & T_OPTION_MASK))
1554 				goto parse_error;
1555 			options.flags |= T_OPTION_MASK;
1556 			break;
1557 
1558 		case 'D': /* image destination  */
1559 			options.image_dest = strtoul(optarg, &endptr, 16);
1560 			if (*endptr || (options.flags & D_OPTION_MASK))
1561 				goto parse_error;
1562 			options.flags |= D_OPTION_MASK;
1563 			DB("Image destination address %#x\n",
1564 			   options.image_dest);
1565 			break;
1566 
1567 		case 'E': /* image execution  */
1568 			options.image_exec = strtoul(optarg, &endptr, 16);
1569 			if (*endptr || (options.flags & E_OPTION_MASK))
1570 				goto parse_error;
1571 			options.flags |= E_OPTION_MASK;
1572 			DB("Image execution address %#x\n", options.image_exec);
1573 			break;
1574 
1575 		case 'X': /* Pre - Padding */
1576 			options.prepadding_size = strtoul(optarg, &endptr, 16);
1577 			if (*endptr || (options.flags & X_OPTION_MASK))
1578 				goto parse_error;
1579 			options.pre_padding = 1;
1580 			options.flags |= X_OPTION_MASK;
1581 			DB("Pre-pad image by %#x bytes\n",
1582 			   options.prepadding_size);
1583 			break;
1584 
1585 		case 'Y': /* Post - Padding */
1586 			options.postpadding_size = strtoul(optarg, &endptr, 16);
1587 			if (*endptr || (options.flags & Y_OPTION_MASK))
1588 				goto parse_error;
1589 			options.post_padding = 1;
1590 			options.flags |= Y_OPTION_MASK;
1591 			DB("Post-pad image by %#x bytes\n",
1592 			   options.postpadding_size);
1593 			break;
1594 
1595 		case 'S': /* starting sector */
1596 			options.image_source = strtoul(optarg, &endptr, 16);
1597 			if (*endptr || (options.flags & S_OPTION_MASK))
1598 				goto parse_error;
1599 			options.flags |= S_OPTION_MASK;
1600 			DB("Image start sector (image source) %#x\n",
1601 			   options.image_source);
1602 			break;
1603 
1604 		case 'P': /* NAND Page Size */
1605 			options.nandPageSize = strtoul(optarg, &endptr, 10);
1606 			if (*endptr || (options.flags & P_OPTION_MASK))
1607 				goto parse_error;
1608 			options.flags |= P_OPTION_MASK;
1609 			DB("NAND page size %d bytes\n", options.nandPageSize);
1610 			break;
1611 
1612 		case 'C': /* headers definition filename */
1613 			options.fname_list = optarg;
1614 			if (options.flags & C_OPTION_MASK)
1615 				goto parse_error;
1616 			options.flags |= C_OPTION_MASK;
1617 			DB("Headers definition file name %s\n",
1618 			   options.fname_list);
1619 			break;
1620 
1621 		case 'W': /* HEX file width */
1622 			options.hex_width = strtoul(optarg, &endptr, 10);
1623 			if (*endptr || (options.flags & W_OPTION_MASK))
1624 				goto parse_error;
1625 			options.flags |= W_OPTION_MASK;
1626 			DB("HEX file width %d bytes\n", options.hex_width);
1627 			break;
1628 
1629 		case 'H': /* Header file mode */
1630 			options.header_mode = strtoul(optarg, &endptr, 10);
1631 			if (*endptr || (options.flags & H_OPTION_MASK))
1632 				goto parse_error;
1633 			options.flags |= H_OPTION_MASK;
1634 			DB("Header file mode is %d\n", options.header_mode);
1635 			break;
1636 
1637 		case 'R': /* dram file */
1638 			options.fname_dram = optarg;
1639 			if (options.flags & R_OPTION_MASK)
1640 				goto parse_error;
1641 			options.flags |= R_OPTION_MASK;
1642 			DB("Registers header file name %s\n",
1643 			   options.fname_dram);
1644 			break;
1645 
1646 		case 'M': /* TWSI file */
1647 			options.fname_twsi = optarg;
1648 			if (options.flags & M_OPTION_MASK)
1649 				goto parse_error;
1650 			options.flags |= M_OPTION_MASK;
1651 			DB("TWSI header file name %s\n", options.fname_twsi);
1652 			break;
1653 
1654 		case 'G': /* binary file */
1655 			options.fname_bin = optarg;
1656 			if (options.flags & G_OPTION_MASK)
1657 				goto parse_error;
1658 			options.flags |= G_OPTION_MASK;
1659 			DB("Binary header file name %s\n", options.fname_bin);
1660 			break;
1661 
1662 		case 'L': /* NAND block size */
1663 			options.nandBlkSize = strtoul(optarg, &endptr, 10) / 64;
1664 			if (*endptr || (options.flags & L_OPTION_MASK))
1665 				goto parse_error;
1666 			options.flags |= L_OPTION_MASK;
1667 			DB("NAND block size %d\n", options.nandBlkSize);
1668 			break;
1669 
1670 		case 'N': /* NAND cell technology */
1671 			options.nandCellTech = optarg[0];
1672 			if (options.flags & N_OPTION_MASK)
1673 				goto parse_error;
1674 			options.flags |= N_OPTION_MASK;
1675 			DB("NAND cell technology %c\n", options.nandCellTech);
1676 			break;
1677 
1678 		case 'p': /* BootROM debug output */
1679 			if (options.flags & p_OPTION_MASK)
1680 				goto parse_error;
1681 			options.flags |= p_OPTION_MASK;
1682 			DB("BootROM debug output disabled\n");
1683 			break;
1684 
1685 		case 'b': /* BootROM debug port baudrate */
1686 			options.baudRate = strtoul(optarg, &endptr, 10);
1687 			if (*endptr || (options.flags & b_OPTION_MASK))
1688 				goto parse_error;
1689 			options.flags |= b_OPTION_MASK;
1690 			DB("BootROM debug port baudrate %d\n",
1691 			   options.baudRate);
1692 			break;
1693 
1694 		case 'u': /* BootROM debug port number */
1695 			options.debugPortNum = strtoul(optarg, &endptr, 10);
1696 			if (*endptr || (options.flags & u_OPTION_MASK))
1697 				goto parse_error;
1698 			options.flags |= u_OPTION_MASK;
1699 			DB("BootROM debug port number %d\n",
1700 			   options.debugPortNum);
1701 			break;
1702 
1703 		case 'm': /* BootROM debug port MPP settings */
1704 			options.debugPortMpp = strtoul(optarg, &endptr, 10);
1705 			if (*endptr || (options.flags & m_OPTION_MASK))
1706 				goto parse_error;
1707 			options.flags |= m_OPTION_MASK;
1708 			DB("BootROM debug port MPP setup # %d\n",
1709 			   options.debugPortMpp);
1710 			break;
1711 
1712 		default:
1713 			goto parse_error;
1714 		}
1715 	} /* parse command-line options */
1716 
1717 	/* assign file names */
1718 	for (i = 0; (optind < argc) && (i < ARRAY_SIZE(options.fname_arr));
1719 	     ++optind, i++) {
1720 		options.fname_arr[i] = argv[optind];
1721 		DB("File @ array index %d is %s (option index is %d)\n", i,
1722 		   argv[optind], optind);
1723 		/* verify that all file names are different */
1724 		for (k = 0; k < i; k++) {
1725 			if (0 == strcmp(options.fname_arr[i],
1726 					options.fname_arr[k])) {
1727 				fprintf(stderr,
1728 				    "\nError: Input and output images can't be the same\n");
1729 				exit(1);
1730 			}
1731 		}
1732 	}
1733 
1734 	if (!(options.flags & T_OPTION_MASK))
1735 		goto parse_error;
1736 
1737 	/* verify HEX/BIN file width selection to be valid */
1738 	if ((options.flags & W_OPTION_MASK) && (options.hex_width != 8) &&
1739 	    (options.hex_width != 16) && (options.hex_width != 32) &&
1740 	    (options.hex_width != 64))
1741 		goto parse_error;
1742 	/* BootROM test images, no header is needed */
1743 	if ((options.image_type == IMG_BOOTROM) ||
1744 	    (options.image_type == IMG_HEX) || (options.image_type == IMG_BIN))
1745 		options.header_mode = IMG_ONLY;
1746 
1747 	if (options.header_mode == IMG_ONLY) {
1748 		/* remove unneeded options */
1749 		options.req_flags &=
1750 		    ~(D_OPTION_MASK | E_OPTION_MASK | S_OPTION_MASK |
1751 		      R_OPTION_MASK | P_OPTION_MASK | L_OPTION_MASK |
1752 		      N_OPTION_MASK);
1753 	}
1754 
1755 	if (options.req_flags != (options.flags & options.req_flags))
1756 		goto parse_error;
1757 
1758 	if ((options.flags & L_OPTION_MASK) &&
1759 	    ((options.nandBlkSize > 255) ||
1760 	     ((options.nandBlkSize == 0) && (options.nandPageSize != 512)))) {
1761 		fprintf(stderr, "Error: wrong NAND block size %d!\n\n\n\n\n",
1762 			64 * options.nandBlkSize);
1763 		goto parse_error;
1764 	}
1765 
1766 	if ((options.flags & N_OPTION_MASK) && (options.nandCellTech != 'S') &&
1767 	    (options.nandCellTech != 'M') && (options.nandCellTech != 's') &&
1768 	    (options.nandCellTech != 'm')) {
1769 		fprintf(stderr,
1770 			"Error: Wrong NAND cell technology type!\n\n\n\n\n");
1771 		goto parse_error;
1772 	}
1773 
1774 	return process_image(&options);
1775 
1776 parse_error:
1777 
1778 	print_usage();
1779 	exit(1);
1780 
1781 } /* end of main() */
1782