xref: /rk3399_rockchip-uboot/tools/rockchip/boot_merger.c (revision 2e6f3f4c09e03d35bfc9e08fa7b7bb5fa6fee0a1)
1 /*
2  * (C) Copyright 2008-2015 Fuzhou Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:	GPL-2.0+
5  */
6 #include "boot_merger.h"
7 #include <time.h>
8 #include <sys/stat.h>
9 #include <version.h>
10 
11 /* #define USE_P_RC4 */
12 
13 bool gDebug =
14 #ifdef DEBUG
15         true;
16 #else
17         false;
18 #endif /* DEBUG */
19 
20 #define ENTRY_ALIGN (2048)
21 options gOpts;
22 char gLegacyPath[MAX_LINE_LEN] = { 0 };
23 char gNewPath[MAX_LINE_LEN] = { 0 };
24 static char *gPrePath;
25 char gSubfix[MAX_LINE_LEN] = OUT_SUBFIX;
26 char gEat[MAX_LINE_LEN];
27 char *gConfigPath;
28 uint8_t *gBuf;
29 
30 static uint32_t g_merge_max_size = MAX_MERGE_SIZE;
31 
32 uint32_t gTable_Crc32[256] = {
33 	0x00000000, 0x04c10db7, 0x09821b6e, 0x0d4316d9, 0x130436dc, 0x17c53b6b,
34 	0x1a862db2, 0x1e472005, 0x26086db8, 0x22c9600f, 0x2f8a76d6, 0x2b4b7b61,
35 	0x350c5b64, 0x31cd56d3, 0x3c8e400a, 0x384f4dbd, 0x4c10db70, 0x48d1d6c7,
36 	0x4592c01e, 0x4153cda9, 0x5f14edac, 0x5bd5e01b, 0x5696f6c2, 0x5257fb75,
37 	0x6a18b6c8, 0x6ed9bb7f, 0x639aada6, 0x675ba011, 0x791c8014, 0x7ddd8da3,
38 	0x709e9b7a, 0x745f96cd, 0x9821b6e0, 0x9ce0bb57, 0x91a3ad8e, 0x9562a039,
39 	0x8b25803c, 0x8fe48d8b, 0x82a79b52, 0x866696e5, 0xbe29db58, 0xbae8d6ef,
40 	0xb7abc036, 0xb36acd81, 0xad2ded84, 0xa9ece033, 0xa4aff6ea, 0xa06efb5d,
41 	0xd4316d90, 0xd0f06027, 0xddb376fe, 0xd9727b49, 0xc7355b4c, 0xc3f456fb,
42 	0xceb74022, 0xca764d95, 0xf2390028, 0xf6f80d9f, 0xfbbb1b46, 0xff7a16f1,
43 	0xe13d36f4, 0xe5fc3b43, 0xe8bf2d9a, 0xec7e202d, 0x34826077, 0x30436dc0,
44 	0x3d007b19, 0x39c176ae, 0x278656ab, 0x23475b1c, 0x2e044dc5, 0x2ac54072,
45 	0x128a0dcf, 0x164b0078, 0x1b0816a1, 0x1fc91b16, 0x018e3b13, 0x054f36a4,
46 	0x080c207d, 0x0ccd2dca, 0x7892bb07, 0x7c53b6b0, 0x7110a069, 0x75d1adde,
47 	0x6b968ddb, 0x6f57806c, 0x621496b5, 0x66d59b02, 0x5e9ad6bf, 0x5a5bdb08,
48 	0x5718cdd1, 0x53d9c066, 0x4d9ee063, 0x495fedd4, 0x441cfb0d, 0x40ddf6ba,
49 	0xaca3d697, 0xa862db20, 0xa521cdf9, 0xa1e0c04e, 0xbfa7e04b, 0xbb66edfc,
50 	0xb625fb25, 0xb2e4f692, 0x8aabbb2f, 0x8e6ab698, 0x8329a041, 0x87e8adf6,
51 	0x99af8df3, 0x9d6e8044, 0x902d969d, 0x94ec9b2a, 0xe0b30de7, 0xe4720050,
52 	0xe9311689, 0xedf01b3e, 0xf3b73b3b, 0xf776368c, 0xfa352055, 0xfef42de2,
53 	0xc6bb605f, 0xc27a6de8, 0xcf397b31, 0xcbf87686, 0xd5bf5683, 0xd17e5b34,
54 	0xdc3d4ded, 0xd8fc405a, 0x6904c0ee, 0x6dc5cd59, 0x6086db80, 0x6447d637,
55 	0x7a00f632, 0x7ec1fb85, 0x7382ed5c, 0x7743e0eb, 0x4f0cad56, 0x4bcda0e1,
56 	0x468eb638, 0x424fbb8f, 0x5c089b8a, 0x58c9963d, 0x558a80e4, 0x514b8d53,
57 	0x25141b9e, 0x21d51629, 0x2c9600f0, 0x28570d47, 0x36102d42, 0x32d120f5,
58 	0x3f92362c, 0x3b533b9b, 0x031c7626, 0x07dd7b91, 0x0a9e6d48, 0x0e5f60ff,
59 	0x101840fa, 0x14d94d4d, 0x199a5b94, 0x1d5b5623, 0xf125760e, 0xf5e47bb9,
60 	0xf8a76d60, 0xfc6660d7, 0xe22140d2, 0xe6e04d65, 0xeba35bbc, 0xef62560b,
61 	0xd72d1bb6, 0xd3ec1601, 0xdeaf00d8, 0xda6e0d6f, 0xc4292d6a, 0xc0e820dd,
62 	0xcdab3604, 0xc96a3bb3, 0xbd35ad7e, 0xb9f4a0c9, 0xb4b7b610, 0xb076bba7,
63 	0xae319ba2, 0xaaf09615, 0xa7b380cc, 0xa3728d7b, 0x9b3dc0c6, 0x9ffccd71,
64 	0x92bfdba8, 0x967ed61f, 0x8839f61a, 0x8cf8fbad, 0x81bbed74, 0x857ae0c3,
65 	0x5d86a099, 0x5947ad2e, 0x5404bbf7, 0x50c5b640, 0x4e829645, 0x4a439bf2,
66 	0x47008d2b, 0x43c1809c, 0x7b8ecd21, 0x7f4fc096, 0x720cd64f, 0x76cddbf8,
67 	0x688afbfd, 0x6c4bf64a, 0x6108e093, 0x65c9ed24, 0x11967be9, 0x1557765e,
68 	0x18146087, 0x1cd56d30, 0x02924d35, 0x06534082, 0x0b10565b, 0x0fd15bec,
69 	0x379e1651, 0x335f1be6, 0x3e1c0d3f, 0x3add0088, 0x249a208d, 0x205b2d3a,
70 	0x2d183be3, 0x29d93654, 0xc5a71679, 0xc1661bce, 0xcc250d17, 0xc8e400a0,
71 	0xd6a320a5, 0xd2622d12, 0xdf213bcb, 0xdbe0367c, 0xe3af7bc1, 0xe76e7676,
72 	0xea2d60af, 0xeeec6d18, 0xf0ab4d1d, 0xf46a40aa, 0xf9295673, 0xfde85bc4,
73 	0x89b7cd09, 0x8d76c0be, 0x8035d667, 0x84f4dbd0, 0x9ab3fbd5, 0x9e72f662,
74 	0x9331e0bb, 0x97f0ed0c, 0xafbfa0b1, 0xab7ead06, 0xa63dbbdf, 0xa2fcb668,
75 	0xbcbb966d, 0xb87a9bda, 0xb5398d03, 0xb1f880b4,
76 };
77 
78 uint32_t CRC_32(uint8_t *pData, uint32_t ulSize)
79 {
80 	uint32_t i;
81 	uint32_t nAccum = 0;
82 	for (i = 0; i < ulSize; i++) {
83 		nAccum = (nAccum << 8) ^ gTable_Crc32[(nAccum >> 24) ^ (*pData++)];
84 	}
85 	return nAccum;
86 }
87 
88 void P_RC4(uint8_t *buf, uint32_t len)
89 {
90 	uint8_t S[256], K[256], temp;
91 	uint32_t i, j, t, x;
92 	uint8_t key[16] = { 124, 78, 3, 4, 85, 5, 9, 7, 45, 44, 123, 56, 23, 13, 23,
93 	                    17
94 	                  };
95 
96 	j = 0;
97 	for (i = 0; i < 256; i++) {
98 		S[i] = (uint8_t) i;
99 		j &= 0x0f;
100 		K[i] = key[j];
101 		j++;
102 	}
103 
104 	j = 0;
105 	for (i = 0; i < 256; i++) {
106 		j = (j + S[i] + K[i]) % 256;
107 		temp = S[i];
108 		S[i] = S[j];
109 		S[j] = temp;
110 	}
111 
112 	i = j = 0;
113 	for (x = 0; x < len; x++) {
114 		i = (i + 1) % 256;
115 		j = (j + S[i]) % 256;
116 		temp = S[i];
117 		S[i] = S[j];
118 		S[j] = temp;
119 		t = (S[i] + (S[j] % 256)) % 256;
120 		buf[x] = buf[x] ^ S[t];
121 	}
122 }
123 
124 static inline void fixPath(char *path)
125 {
126 	int i, len = strlen(path);
127 	char tmp[MAX_LINE_LEN];
128 	char *start, *end;
129 
130 	for (i = 0; i < len; i++) {
131 		if (path[i] == '\\')
132 			path[i] = '/';
133 		else if (path[i] == '\r' || path[i] == '\n')
134 			path[i] = '\0';
135 	}
136 
137 	if (strlen(gLegacyPath) && strlen(gNewPath)) {
138 		start = strstr(path, gLegacyPath);
139 		if (start) {
140 			end = start + strlen(gLegacyPath);
141 			/* Backup, so tmp can be src for strcat() */
142 			strcpy(tmp, end);
143 			/* Terminate, so path can be dest for strcat() */
144 			*start = '\0';
145 			strcat(path, gNewPath);
146 			strcat(path, tmp);
147 		} else {
148 			strcpy(tmp, path);
149 			strcpy(path, gNewPath);
150 			strcat(path, tmp);
151 		}
152 	} else if (gPrePath && strncmp(path, gPrePath, strlen(gPrePath))) {
153 		strcpy(tmp, path);
154 		strcpy(path, gPrePath);
155 		strcat(path, tmp);
156 	}
157 }
158 
159 static bool parseChip(FILE *file)
160 {
161 	if (SCANF_EAT(file) != 0) {
162 		return false;
163 	}
164 	if (fscanf(file, OPT_NAME "=%s", gOpts.chip) != 1) {
165 		return false;
166 	}
167 	LOGD("chip:%s\n", gOpts.chip);
168 	return true;
169 }
170 
171 static bool parseVersion(FILE *file)
172 {
173 	if (SCANF_EAT(file) != 0) {
174 		return false;
175 	}
176 	if (fscanf(file, OPT_MAJOR "=%d", &gOpts.major) != 1)
177 		return false;
178 	if (SCANF_EAT(file) != 0) {
179 		return false;
180 	}
181 	if (fscanf(file, OPT_MINOR "=%d", &gOpts.minor) != 1)
182 		return false;
183 	LOGD("major:%d, minor:%d\n", gOpts.major, gOpts.minor);
184 	return true;
185 }
186 
187 static bool parse471(FILE *file)
188 {
189 	int i, index, pos;
190 	char buf[MAX_LINE_LEN];
191 
192 	if (SCANF_EAT(file) != 0) {
193 		return false;
194 	}
195 	if (fscanf(file, OPT_NUM "=%d", &gOpts.code471Num) != 1)
196 		return false;
197 	LOGD("num:%d\n", gOpts.code471Num);
198 	if (!gOpts.code471Num)
199 		return true;
200 	if (gOpts.code471Num < 0)
201 		return false;
202 	gOpts.code471Path = (line_t *)malloc(sizeof(line_t) * gOpts.code471Num);
203 	for (i = 0; i < gOpts.code471Num; i++) {
204 		if (SCANF_EAT(file) != 0) {
205 			return false;
206 		}
207 		if (fscanf(file, OPT_PATH "%d=%[^\r^\n]", &index, buf) != 2)
208 			return false;
209 		index--;
210 		fixPath(buf);
211 		strcpy((char *)gOpts.code471Path[index], buf);
212 		LOGD("path%i:%s\n", index, gOpts.code471Path[index]);
213 	}
214 	pos = ftell(file);
215 	if (SCANF_EAT(file) != 0) {
216 		return false;
217 	}
218 	if (fscanf(file, OPT_SLEEP "=%d", &gOpts.code471Sleep) != 1)
219 		fseek(file, pos, SEEK_SET);
220 	LOGD("sleep:%d\n", gOpts.code471Sleep);
221 	return true;
222 }
223 
224 static bool parse472(FILE *file)
225 {
226 	int i, index, pos;
227 	char buf[MAX_LINE_LEN];
228 
229 	if (SCANF_EAT(file) != 0) {
230 		return false;
231 	}
232 	if (fscanf(file, OPT_NUM "=%d", &gOpts.code472Num) != 1)
233 		return false;
234 	LOGD("num:%d\n", gOpts.code472Num);
235 	if (!gOpts.code472Num)
236 		return true;
237 	if (gOpts.code472Num < 0)
238 		return false;
239 	gOpts.code472Path = (line_t *)malloc(sizeof(line_t) * gOpts.code472Num);
240 	for (i = 0; i < gOpts.code472Num; i++) {
241 		if (SCANF_EAT(file) != 0) {
242 			return false;
243 		}
244 		if (fscanf(file, OPT_PATH "%d=%[^\r^\n]", &index, buf) != 2)
245 			return false;
246 		fixPath(buf);
247 		index--;
248 		strcpy((char *)gOpts.code472Path[index], buf);
249 		LOGD("path%i:%s\n", index, gOpts.code472Path[index]);
250 	}
251 	pos = ftell(file);
252 	if (SCANF_EAT(file) != 0) {
253 		return false;
254 	}
255 	if (fscanf(file, OPT_SLEEP "=%d", &gOpts.code472Sleep) != 1)
256 		fseek(file, pos, SEEK_SET);
257 	LOGD("sleep:%d\n", gOpts.code472Sleep);
258 	return true;
259 }
260 
261 static bool parseLoader(FILE *file)
262 {
263 	int i, j, index, pos;
264 	char buf[MAX_LINE_LEN];
265 	char buf2[MAX_LINE_LEN];
266 
267 	if (SCANF_EAT(file) != 0) {
268 		return false;
269 	}
270 	pos = ftell(file);
271 	if (fscanf(file, OPT_NUM "=%d", &gOpts.loaderNum) != 1) {
272 		fseek(file, pos, SEEK_SET);
273 		if (fscanf(file, OPT_LOADER_NUM "=%d", &gOpts.loaderNum) != 1) {
274 			return false;
275 		}
276 	}
277 	LOGD("num:%d\n", gOpts.loaderNum);
278 	if (!gOpts.loaderNum)
279 		return false;
280 	if (gOpts.loaderNum < 0)
281 		return false;
282 	gOpts.loader = (name_entry *)malloc(sizeof(name_entry) * gOpts.loaderNum);
283 	for (i = 0; i < gOpts.loaderNum; i++) {
284 		if (SCANF_EAT(file) != 0) {
285 			return false;
286 		}
287 		if (fscanf(file, OPT_LOADER_NAME "%d=%s", &index, buf) != 2)
288 			return false;
289 		index--;
290 		strcpy(gOpts.loader[index].name, buf);
291 		LOGD("name%d:%s\n", index, gOpts.loader[index].name);
292 	}
293 	for (i = 0; i < gOpts.loaderNum; i++) {
294 		if (SCANF_EAT(file) != 0) {
295 			return false;
296 		}
297 		if (fscanf(file, "%[^=]=%[^\r^\n]", buf, buf2) != 2)
298 			return false;
299 		for (j = 0; j < gOpts.loaderNum; j++) {
300 			if (!strcmp(gOpts.loader[j].name, buf)) {
301 				fixPath(buf2);
302 				strcpy(gOpts.loader[j].path, buf2);
303 				LOGD("%s=%s\n", gOpts.loader[j].name, gOpts.loader[j].path);
304 				break;
305 			}
306 		}
307 		if (j >= gOpts.loaderNum) {
308 			return false;
309 		}
310 	}
311 	return true;
312 }
313 
314 static bool parseOut(FILE *file)
315 {
316 	if (SCANF_EAT(file) != 0) {
317 		return false;
318 	}
319 	if (fscanf(file, OPT_OUT_PATH "=%[^\r^\n]", gOpts.outPath) != 1)
320 		return false;
321 	printf("out:%s\n", gOpts.outPath);
322 	return true;
323 }
324 
325 void printOpts(FILE *out)
326 {
327 	uint32_t i;
328 	fprintf(out, SEC_CHIP "\n" OPT_NAME "=%s\n", gOpts.chip);
329 	fprintf(out, SEC_VERSION "\n" OPT_MAJOR "=%d\n" OPT_MINOR "=%d\n",
330 	        gOpts.major, gOpts.minor);
331 
332 	fprintf(out, SEC_471 "\n" OPT_NUM "=%d\n", gOpts.code471Num);
333 	for (i = 0; i < gOpts.code471Num; i++) {
334 		fprintf(out, OPT_PATH "%d=%s\n", i + 1, gOpts.code471Path[i]);
335 	}
336 	if (gOpts.code471Sleep > 0)
337 		fprintf(out, OPT_SLEEP "=%d\n", gOpts.code471Sleep);
338 
339 	fprintf(out, SEC_472 "\n" OPT_NUM "=%d\n", gOpts.code472Num);
340 	for (i = 0; i < gOpts.code472Num; i++) {
341 		fprintf(out, OPT_PATH "%d=%s\n", i + 1, gOpts.code472Path[i]);
342 	}
343 	if (gOpts.code472Sleep > 0)
344 		fprintf(out, OPT_SLEEP "=%d\n", gOpts.code472Sleep);
345 
346 	fprintf(out, SEC_LOADER "\n" OPT_NUM "=%d\n", gOpts.loaderNum);
347 	for (i = 0; i < gOpts.loaderNum; i++) {
348 		fprintf(out, OPT_LOADER_NAME "%d=%s\n", i + 1, gOpts.loader[i].name);
349 	}
350 	for (i = 0; i < gOpts.loaderNum; i++) {
351 		fprintf(out, "%s=%s\n", gOpts.loader[i].name, gOpts.loader[i].path);
352 	}
353 
354 	fprintf(out, SEC_OUT "\n" OPT_OUT_PATH "=%s\n", gOpts.outPath);
355 }
356 
357 static bool parseOpts_from_file(void)
358 {
359 	bool ret = false;
360 	bool chipOk = false;
361 	bool versionOk = false;
362 	bool code471Ok = true;
363 	bool code472Ok = true;
364 	bool loaderOk = false;
365 	bool outOk = false;
366 	char buf[MAX_LINE_LEN];
367 
368 	char *configPath = (gConfigPath == NULL) ? DEF_CONFIG_FILE : gConfigPath;
369 	FILE *file;
370 	file = fopen(configPath, "r");
371 	if (!file) {
372 		fprintf(stderr, "config(%s) not found!\n", configPath);
373 		if (configPath == (char *)DEF_CONFIG_FILE) {
374 			file = fopen(DEF_CONFIG_FILE, "w");
375 			if (file) {
376 				fprintf(stderr, "create defconfig\n");
377 				printOpts(file);
378 			}
379 		}
380 		goto end;
381 	}
382 
383 	LOGD("start parse\n");
384 
385 	if (SCANF_EAT(file) != 0) {
386 		goto end;
387 	}
388 	while (fscanf(file, "%s", buf) == 1) {
389 		if (!strcmp(buf, SEC_CHIP)) {
390 			chipOk = parseChip(file);
391 			if (!chipOk) {
392 				LOGE("parseChip failed!\n");
393 				goto end;
394 			}
395 		} else if (!strcmp(buf, SEC_VERSION)) {
396 			versionOk = parseVersion(file);
397 			if (!versionOk) {
398 				LOGE("parseVersion failed!\n");
399 				goto end;
400 			}
401 		} else if (!strcmp(buf, SEC_471)) {
402 			code471Ok = parse471(file);
403 			if (!code471Ok) {
404 				LOGE("parse471 failed!\n");
405 				goto end;
406 			}
407 		} else if (!strcmp(buf, SEC_472)) {
408 			code472Ok = parse472(file);
409 			if (!code472Ok) {
410 				LOGE("parse472 failed!\n");
411 				goto end;
412 			}
413 		} else if (!strcmp(buf, SEC_LOADER)) {
414 			loaderOk = parseLoader(file);
415 			if (!loaderOk) {
416 				LOGE("parseLoader failed!\n");
417 				goto end;
418 			}
419 		} else if (!strcmp(buf, SEC_OUT)) {
420 			outOk = parseOut(file);
421 			if (!outOk) {
422 				LOGE("parseOut failed!\n");
423 				goto end;
424 			}
425 		} else if (buf[0] == '#') {
426 			continue;
427 		} else {
428 			LOGE("unknown sec: %s!\n", buf);
429 			goto end;
430 		}
431 		if (SCANF_EAT(file) != 0) {
432 			goto end;
433 		}
434 	}
435 
436 	if (chipOk && versionOk && code471Ok && code472Ok && loaderOk && outOk)
437 		ret = true;
438 end:
439 	if (file)
440 		fclose(file);
441 	return ret;
442 }
443 
444 static bool parseOpts_from_cmdline(int argc, char **argv)
445 {
446 	int i;
447 	int tag = 0;
448 	int v0, v1, v2, v3;
449 
450 	for (i = 2; i < argc; i++) {
451 		if (!strcmp(OPT_471, argv[i])) {
452 			i++;
453 			snprintf(gOpts.code471Path[0], sizeof(gOpts.code471Path[0]), "%s",
454 			         argv[i]);
455 			tag |= 1;
456 		} else if (!strcmp(OPT_472, argv[i])) {
457 			i++;
458 			snprintf(gOpts.code472Path[0], sizeof(gOpts.code472Path[0]), "%s",
459 			         argv[i]);
460 			tag |= 2;
461 		} else if (!strcmp(OPT_DATA, argv[i])) {
462 			i++;
463 			snprintf(gOpts.loader[0].path, sizeof(gOpts.loader[0].path), "%s",
464 			         argv[i]);
465 			tag |= 4;
466 		} else if (!strcmp(OPT_BOOT, argv[i])) {
467 			i++;
468 			snprintf(gOpts.loader[1].path, sizeof(gOpts.loader[1].path), "%s",
469 			         argv[i]);
470 			tag |= 8;
471 		} else if (!strcmp(OPT_OUT, argv[i])) {
472 			i++;
473 			snprintf(gOpts.outPath, sizeof(gOpts.outPath), "%s", argv[i]);
474 			tag |= 0x10;
475 		} else if (!strcmp(OPT_CHIP, argv[i])) {
476 			i++;
477 			snprintf(gOpts.chip, sizeof(gOpts.chip), "%s", argv[i]);
478 			tag |= 0x20;
479 		} else if (!strcmp(OPT_VERSION, argv[i])) {
480 		}
481 	}
482 
483 	sscanf(gOpts.loader[0].path, "%*[^v]v%d.%d.bin", &v0, &v1);
484 	sscanf(gOpts.loader[1].path, "%*[^v]v%d.%d.bin", &v2, &v3);
485 	gOpts.major = v2;
486 	gOpts.minor = v3;
487 	snprintf(gOpts.outPath, sizeof(gOpts.outPath),
488 	         "%s_loader_v%d.%02d.%d%02d.bin", gOpts.chip, v0, v1, v2, v3);
489 	return ((tag & 0x0f) == 0x0f) ? true : false;
490 }
491 
492 bool initOpts(int argc, char **argv)
493 {
494 	bool ret;
495 
496 	/* set default opts */
497 	gOpts.major = DEF_MAJOR;
498 	gOpts.minor = DEF_MINOR;
499 	strcpy(gOpts.chip, DEF_CHIP);
500 	gOpts.code471Sleep = DEF_CODE471_SLEEP;
501 	gOpts.code472Sleep = DEF_CODE472_SLEEP;
502 	gOpts.code471Num = DEF_CODE471_NUM;
503 	gOpts.code471Path = (line_t *)malloc(sizeof(line_t) * gOpts.code471Num);
504 	strcpy((char *)gOpts.code471Path[0], DEF_CODE471_PATH);
505 	gOpts.code472Num = DEF_CODE472_NUM;
506 	gOpts.code472Path = (line_t *)malloc(sizeof(line_t) * gOpts.code472Num);
507 	strcpy((char *)gOpts.code472Path[0], DEF_CODE472_PATH);
508 	gOpts.loaderNum = DEF_LOADER_NUM;
509 	gOpts.loader = (name_entry *)malloc(sizeof(name_entry) * gOpts.loaderNum);
510 	strcpy(gOpts.loader[0].name, DEF_LOADER0);
511 	strcpy(gOpts.loader[0].path, DEF_LOADER0_PATH);
512 	strcpy(gOpts.loader[1].name, DEF_LOADER1);
513 	strcpy(gOpts.loader[1].path, DEF_LOADER1_PATH);
514 	strcpy(gOpts.outPath, DEF_OUT_PATH);
515 
516 	if (argc > 10)
517 		ret = parseOpts_from_cmdline(argc, argv);
518 	else
519 		ret = parseOpts_from_file();
520 
521 	return ret;
522 }
523 
524 /************merge code****************/
525 
526 static inline uint32_t getBCD(unsigned short value)
527 {
528 	uint8_t tmp[2] = { 0 };
529 	int i;
530 	uint32_t ret;
531 	if (value > 0xFFFF) {
532 		return 0;
533 	}
534 	for (i = 0; i < 2; i++) {
535 		tmp[i] = (((value / 10) % 10) << 4) | (value % 10);
536 		value /= 100;
537 	}
538 	ret = ((uint16_t)(tmp[1] << 8)) | tmp[0];
539 
540 	LOGD("ret:%x\n", ret);
541 	return ret & 0xFF;
542 }
543 
544 static inline void str2wide(const char *str, uint16_t *wide, int len)
545 {
546 	int i;
547 	for (i = 0; i < len; i++) {
548 		wide[i] = (uint16_t) str[i];
549 	}
550 	wide[len] = 0;
551 }
552 
553 static inline void getName(char *path, uint16_t *dst)
554 {
555 	char *end;
556 	char *start;
557 	int len;
558 	if (!path || !dst)
559 		return;
560 	start = strrchr(path, '/');
561 	if (!start)
562 		start = path;
563 	else
564 		start++;
565 	end = strrchr(path, '.');
566 	if (!end)
567 		end = path + strlen(path);
568 	len = end - start;
569 	if (len >= MAX_NAME_LEN)
570 		len = MAX_NAME_LEN - 1;
571 	str2wide(start, dst, len);
572 
573 	if (gDebug) {
574 		char name[MAX_NAME_LEN];
575 		memset(name, 0, sizeof(name));
576 		memcpy(name, start, len);
577 		LOGD("path:%s, name:%s\n", path, name);
578 	}
579 }
580 
581 static inline bool getFileSize(const char *path, uint32_t *size)
582 {
583 	struct stat st;
584 	if (stat(path, &st) < 0)
585 		return false;
586 	*size = st.st_size;
587 	LOGD("path:%s, size:%d\n", path, *size);
588 	return true;
589 }
590 
591 static inline rk_time getTime(void)
592 {
593 	rk_time rkTime;
594 
595 	struct tm *tm;
596 	time_t tt = time(NULL);
597 	tm = localtime(&tt);
598 	rkTime.year = tm->tm_year + 1900;
599 	rkTime.month = tm->tm_mon + 1;
600 	rkTime.day = tm->tm_mday;
601 	rkTime.hour = tm->tm_hour;
602 	rkTime.minute = tm->tm_min;
603 	rkTime.second = tm->tm_sec;
604 	LOGD("%d-%d-%d %02d:%02d:%02d\n", rkTime.year, rkTime.month, rkTime.day,
605 	     rkTime.hour, rkTime.minute, rkTime.second);
606 	return rkTime;
607 }
608 
609 static bool writeFile(FILE *outFile, const char *path, bool fix)
610 {
611 	bool ret = false;
612 	uint32_t size = 0, fixSize = 0;
613 	uint8_t *buf;
614 
615 	FILE *inFile = fopen(path, "rb");
616 	if (!inFile)
617 		goto end;
618 
619 	if (!getFileSize(path, &size))
620 		goto end;
621 	if (fix) {
622 		fixSize = ((size - 1) / SMALL_PACKET + 1) * SMALL_PACKET;
623 		uint32_t tmp = fixSize % ENTRY_ALIGN;
624 		tmp = tmp ? (ENTRY_ALIGN - tmp) : 0;
625 		fixSize += tmp;
626 		memset(gBuf, 0, fixSize);
627 	} else {
628 		memset(gBuf, 0, size + ENTRY_ALIGN);
629 	}
630 	if (!fread(gBuf, size, 1, inFile))
631 		goto end;
632 
633 	if (fix) {
634 
635 		buf = gBuf;
636 		size = fixSize;
637 		while (1) {
638 			P_RC4(buf, fixSize < SMALL_PACKET ? fixSize : SMALL_PACKET);
639 			buf += SMALL_PACKET;
640 			if (fixSize <= SMALL_PACKET)
641 				break;
642 			fixSize -= SMALL_PACKET;
643 		}
644 	} else {
645 		uint32_t tmp = size % ENTRY_ALIGN;
646 		tmp = tmp ? (ENTRY_ALIGN - tmp) : 0;
647 		size += tmp;
648 		P_RC4(gBuf, size);
649 	}
650 
651 	if (!fwrite(gBuf, size, 1, outFile))
652 		goto end;
653 	ret = true;
654 end:
655 	if (inFile)
656 		fclose(inFile);
657 	if (!ret)
658 		LOGE("write entry(%s) failed\n", path);
659 	return ret;
660 }
661 
662 static bool saveEntry(FILE *outFile, char *path, rk_entry_type type,
663                       uint16_t delay, uint32_t *offset, char *fixName,
664                       bool fix)
665 {
666 	LOGD("write:%s\n", path);
667 	uint32_t size;
668 	rk_boot_entry entry;
669 	memset(&entry, 0, sizeof(rk_boot_entry));
670 
671 	LOGD("write:%s\n", path);
672 
673 	getName(fixName ? fixName : path, entry.name);
674 	entry.size = sizeof(rk_boot_entry);
675 	entry.type = type;
676 	entry.dataOffset = *offset;
677 	if (!getFileSize(path, &size)) {
678 		LOGE("save entry(%s) failed:\n\tcannot get file size.\n", path);
679 		return false;
680 	}
681 	if (fix)
682 		size = ((size - 1) / SMALL_PACKET + 1) * SMALL_PACKET;
683 	uint32_t tmp = size % ENTRY_ALIGN;
684 	size += tmp ? (ENTRY_ALIGN - tmp) : 0;
685 	LOGD("align size:%d\n", size);
686 	entry.dataSize = size;
687 	entry.dataDelay = delay;
688 	*offset += size;
689 	fwrite(&entry, sizeof(rk_boot_entry), 1, outFile);
690 	return true;
691 }
692 
693 static inline uint32_t convertChipType(const char *chip)
694 {
695 	char buffer[5];
696 	memset(buffer, 0, sizeof(buffer));
697 	snprintf(buffer, sizeof(buffer), "%s", chip);
698 	return buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
699 }
700 
701 static inline uint32_t getChipType(const char *chip)
702 {
703 	LOGD("chip:%s\n", chip);
704 	int chipType = RKNONE_DEVICE;
705 	if (!chip) {
706 		goto end;
707 	}
708 	if (!strcmp(chip, CHIP_RK28)) {
709 		chipType = RK28_DEVICE;
710 	} else if (!strcmp(chip, CHIP_RK28)) {
711 		chipType = RK28_DEVICE;
712 	} else if (!strcmp(chip, CHIP_RK281X)) {
713 		chipType = RK281X_DEVICE;
714 	} else if (!strcmp(chip, CHIP_RKPANDA)) {
715 		chipType = RKPANDA_DEVICE;
716 	} else if (!strcmp(chip, CHIP_RK27)) {
717 		chipType = RK27_DEVICE;
718 	} else if (!strcmp(chip, CHIP_RKNANO)) {
719 		chipType = RKNANO_DEVICE;
720 	} else if (!strcmp(chip, CHIP_RKSMART)) {
721 		chipType = RKSMART_DEVICE;
722 	} else if (!strcmp(chip, CHIP_RKCROWN)) {
723 		chipType = RKCROWN_DEVICE;
724 	} else if (!strcmp(chip, CHIP_RKCAYMAN)) {
725 		chipType = RKCAYMAN_DEVICE;
726 	} else if (!strcmp(chip, CHIP_RK29)) {
727 		chipType = RK29_DEVICE;
728 	} else if (!strcmp(chip, CHIP_RK292X)) {
729 		chipType = RK292X_DEVICE;
730 	} else if (!strcmp(chip, CHIP_RK30)) {
731 		chipType = RK30_DEVICE;
732 	} else if (!strcmp(chip, CHIP_RK30B)) {
733 		chipType = RK30B_DEVICE;
734 	} else if (!strcmp(chip, CHIP_RK31)) {
735 		chipType = RK31_DEVICE;
736 	} else if (!strcmp(chip, CHIP_RK32)) {
737 		chipType = RK32_DEVICE;
738 	} else {
739 		chipType = convertChipType(chip + 2);
740 	}
741 
742 end:
743 	LOGD("type:0x%x\n", chipType);
744 	if (chipType == RKNONE_DEVICE) {
745 		LOGE("chip type not support!\n");
746 	}
747 	return chipType;
748 }
749 
750 static inline void getBoothdr(rk_boot_header *hdr)
751 {
752 	memset(hdr, 0, sizeof(rk_boot_header));
753 	hdr->tag = TAG;
754 	hdr->size = sizeof(rk_boot_header);
755 	hdr->version = (getBCD(gOpts.major) << 8) | getBCD(gOpts.minor);
756 	hdr->mergerVersion = MERGER_VERSION;
757 	hdr->releaseTime = getTime();
758 	hdr->chipType = getChipType(gOpts.chip);
759 
760 	hdr->code471Num = gOpts.code471Num;
761 	hdr->code471Offset = sizeof(rk_boot_header);
762 	hdr->code471Size = sizeof(rk_boot_entry);
763 
764 	hdr->code472Num = gOpts.code472Num;
765 	hdr->code472Offset = hdr->code471Offset + gOpts.code471Num * hdr->code471Size;
766 	hdr->code472Size = sizeof(rk_boot_entry);
767 
768 	hdr->loaderNum = gOpts.loaderNum;
769 	hdr->loaderOffset = hdr->code472Offset + gOpts.code472Num * hdr->code472Size;
770 	hdr->loaderSize = sizeof(rk_boot_entry);
771 #ifndef USE_P_RC4
772 	hdr->rc4Flag = 1;
773 #endif
774 }
775 
776 static inline uint32_t getCrc(const char *path)
777 {
778 	uint32_t size = 0;
779 	uint32_t crc = 0;
780 	FILE *file = fopen(path, "rb");
781 	getFileSize(path, &size);
782 	if (!file)
783 		goto end;
784 	if (!fread(gBuf, size, 1, file))
785 		goto end;
786 	crc = CRC_32(gBuf, size);
787 	LOGD("crc:0x%08x\n", crc);
788 end:
789 	if (file)
790 		fclose(file);
791 	return crc;
792 }
793 
794 static bool mergeBoot(int argc, char **argv)
795 {
796 	uint32_t dataOffset;
797 	bool ret = false;
798 	int i;
799 	FILE *outFile;
800 	uint32_t crc;
801 	rk_boot_header hdr;
802 
803 	if (!initOpts(argc, argv))
804 		return false;
805 	{
806 		char *subfix = strstr(gOpts.outPath, OUT_SUBFIX);
807 		char version[MAX_LINE_LEN];
808 		snprintf(version, sizeof(version), "%s", gSubfix);
809 		if (subfix && !strcmp(subfix, OUT_SUBFIX)) {
810 			subfix[0] = '\0';
811 		}
812 		strcat(gOpts.outPath, version);
813 		printf("fix opt:%s\n", gOpts.outPath);
814 	}
815 
816 	if (gDebug) {
817 		printf("---------------\nUSING CONFIG:\n");
818 		printOpts(stdout);
819 		printf("---------------\n\n");
820 	}
821 
822 	outFile = fopen(gOpts.outPath, "wb+");
823 	if (!outFile) {
824 		LOGE("open out file(%s) failed\n", gOpts.outPath);
825 		goto end;
826 	}
827 
828 	getBoothdr(&hdr);
829 	LOGD("write hdr\n");
830 	fwrite(&hdr, 1, sizeof(rk_boot_header), outFile);
831 
832 	dataOffset = sizeof(rk_boot_header) +
833 	             (gOpts.code471Num + gOpts.code472Num + gOpts.loaderNum) *
834 	             sizeof(rk_boot_entry);
835 
836 	LOGD("write code 471 entry\n");
837 	for (i = 0; i < gOpts.code471Num; i++) {
838 		if (!saveEntry(outFile, (char *)gOpts.code471Path[i], ENTRY_471,
839 		               gOpts.code471Sleep, &dataOffset, NULL, false))
840 			goto end;
841 	}
842 	LOGD("write code 472 entry\n");
843 	for (i = 0; i < gOpts.code472Num; i++) {
844 		if (!saveEntry(outFile, (char *)gOpts.code472Path[i], ENTRY_472,
845 		               gOpts.code472Sleep, &dataOffset, NULL, false))
846 			goto end;
847 	}
848 	LOGD("write loader entry\n");
849 	for (i = 0; i < gOpts.loaderNum; i++) {
850 		if (!saveEntry(outFile, gOpts.loader[i].path, ENTRY_LOADER, 0, &dataOffset,
851 		               gOpts.loader[i].name, true))
852 			goto end;
853 	}
854 
855 	LOGD("write code 471\n");
856 	for (i = 0; i < gOpts.code471Num; i++) {
857 		if (!writeFile(outFile, (char *)gOpts.code471Path[i], false))
858 			goto end;
859 	}
860 	LOGD("write code 472\n");
861 	for (i = 0; i < gOpts.code472Num; i++) {
862 		if (!writeFile(outFile, (char *)gOpts.code472Path[i], false))
863 			goto end;
864 	}
865 	LOGD("write loader\n");
866 	for (i = 0; i < gOpts.loaderNum; i++) {
867 		if (!writeFile(outFile, gOpts.loader[i].path, true))
868 			goto end;
869 	}
870 	fflush(outFile);
871 
872 	LOGD("write crc\n");
873 	crc = getCrc(gOpts.outPath);
874 	if (!fwrite(&crc, sizeof(crc), 1, outFile))
875 		goto end;
876 
877 	ret = true;
878 end:
879 	if (outFile)
880 		fclose(outFile);
881 	return ret;
882 }
883 
884 /************merge code end************/
885 /************unpack code***************/
886 
887 static inline void wide2str(const uint16_t *wide, char *str, int len)
888 {
889 	int i;
890 	for (i = 0; i < len; i++) {
891 		str[i] = (char)(wide[i] & 0xFF);
892 	}
893 	str[len] = 0;
894 }
895 
896 static bool unpackEntry(rk_boot_entry *entry, const char *name, FILE *inFile)
897 {
898 	bool ret = false;
899 	int size, i;
900 	FILE *outFile = fopen(name, "wb+");
901 	if (!outFile)
902 		goto end;
903 	printf("unpack entry(%s)\n", name);
904 	fseek(inFile, entry->dataOffset, SEEK_SET);
905 	size = entry->dataSize;
906 	if (!fread(gBuf, size, 1, inFile))
907 		goto end;
908 	if (entry->type == ENTRY_LOADER) {
909 		for (i = 0; i < size / SMALL_PACKET; i++)
910 			P_RC4(gBuf + i * SMALL_PACKET, SMALL_PACKET);
911 		if (size % SMALL_PACKET) {
912 			P_RC4(gBuf + i * SMALL_PACKET, size - SMALL_PACKET * 512);
913 		}
914 	} else {
915 		P_RC4(gBuf, size);
916 	}
917 	if (!fwrite(gBuf, size, 1, outFile))
918 		goto end;
919 	ret = true;
920 end:
921 	if (outFile)
922 		fclose(outFile);
923 	return ret;
924 }
925 
926 static bool unpackBoot(char *path)
927 {
928 	bool ret = false;
929 	FILE *inFile = fopen(path, "rb");
930 	int entryNum, i;
931 	char name[MAX_NAME_LEN];
932 	rk_boot_entry *entrys;
933 	if (!inFile) {
934 		fprintf(stderr, "loader(%s) not found\n", path);
935 		goto end;
936 	}
937 
938 	rk_boot_header hdr;
939 	if (!fread(&hdr, sizeof(rk_boot_header), 1, inFile)) {
940 		fprintf(stderr, "read header failed\n");
941 		goto end;
942 	}
943 
944 	entryNum = hdr.code471Num + hdr.code472Num + hdr.loaderNum;
945 	entrys = (rk_boot_entry *)malloc(sizeof(rk_boot_entry) * entryNum);
946 	if (!fread(entrys, sizeof(rk_boot_entry) * entryNum, 1, inFile)) {
947 		fprintf(stderr, "read data failed\n");
948 		goto end;
949 	}
950 
951 	LOGD("entry num:%d\n", entryNum);
952 	for (i = 0; i < entryNum; i++) {
953 		wide2str(entrys[i].name, name, MAX_NAME_LEN);
954 
955 		LOGD("entry:t=%d, name=%s, off=%d, size=%d\n", entrys[i].type, name,
956 		     entrys[i].dataOffset, entrys[i].dataSize);
957 		if (!unpackEntry(entrys + i, name, inFile)) {
958 			fprintf(stderr, "unpack entry(%s) failed\n", name);
959 			goto end;
960 		}
961 	}
962 
963 	ret = true;
964 end:
965 	if (inFile)
966 		fclose(inFile);
967 	return ret;
968 }
969 
970 /************unpack code end***********/
971 
972 static void printHelp(void)
973 {
974 	printf("Usage1: boot_merger [options]... FILE\n");
975 	printf("Merge or unpack Rockchip's loader (Default action is to merge.)\n");
976 	printf("Options:\n");
977 	printf("\t" OPT_MERGE "\t\t\tMerge loader with specified config.\n");
978 	printf("\t" OPT_UNPACK "\t\tUnpack specified loader to current dir.\n");
979 	printf("\t" OPT_VERBOSE "\t\tDisplay more runtime informations.\n");
980 	printf("\t" OPT_HELP "\t\t\tDisplay this information.\n");
981 	printf("\t" OPT_VERSION "\t\tDisplay version information.\n");
982 	printf("\t" OPT_SUBFIX "\t\tSpec subfix.\n");
983 	printf("\t" OPT_REPLACE "\t\tReplace some part of binary path.\n");
984 	printf("\t" OPT_PREPATH "\t\tAdd prefix path of binary path.\n");
985 	printf("\t" OPT_SIZE
986 	       "\t\tImage size.\"--size [image KB size]\", must be 512KB aligned\n");
987 	printf("Usage2: boot_merger [options] [parameter]\n");
988 	printf("All below five option are must in this mode!\n");
989 	printf("\t" OPT_CHIP "\t\tChip type, used for check with usbplug.\n");
990 	printf("\t" OPT_471 "\t\t471 for download, ddr.bin.\n");
991 	printf("\t" OPT_472 "\t\t472 for download, usbplug.bin.\n");
992 	printf("\t" OPT_DATA "\t\tloader0 for flash, ddr.bin.\n");
993 	printf("\t" OPT_BOOT "\t\tloader1 for flash, miniloader.bin.\n");
994 	printf("\n./tools/boot_merger --pack --verbose -c RK322A -1 "
995 	       "rkbin/rk322x_ddr_300MHz_v1.04.bin -2 "
996 	       "rkbin/rk32/rk322x_usbplug_v2.32.bin -d "
997 	       "rkbin/rk32/rk322x_ddr_300MHz_v1.04.bin -b "
998 	       "rkbin/rk32/rk322x_miniloader_v2.32.bin\n");
999 }
1000 
1001 int main(int argc, char **argv)
1002 {
1003 
1004 	int i;
1005 	bool merge = true;
1006 	char *optPath = NULL;
1007 
1008 	for (i = 1; i < argc; i++) {
1009 		if (!strcmp(OPT_VERBOSE, argv[i])) {
1010 			gDebug = true;
1011 			printf("enable debug\n");
1012 		} else if (!strcmp(OPT_HELP, argv[i])) {
1013 			printHelp();
1014 			return 0;
1015 		} else if (!strcmp(OPT_VERSION, argv[i])) {
1016 			printf("boot_merger (cjf@rock-chips.com)\t" VERSION "\n");
1017 			return 0;
1018 		} else if (!strcmp(OPT_MERGE, argv[i])) {
1019 			merge = true;
1020 		} else if (!strcmp(OPT_UNPACK, argv[i])) {
1021 			merge = false;
1022 		} else if (!strcmp(OPT_SUBFIX, argv[i])) {
1023 			i++;
1024 			snprintf(gSubfix, sizeof(gSubfix), "%s", argv[i]);
1025 		} else if (!strcmp(OPT_REPLACE, argv[i])) {
1026 			i++;
1027 			snprintf(gLegacyPath, sizeof(gLegacyPath), "%s", argv[i]);
1028 			i++;
1029 			snprintf(gNewPath, sizeof(gNewPath), "%s", argv[i]);
1030 		} else if (!strcmp(OPT_PREPATH, argv[i])) {
1031 			i++;
1032 			gPrePath = argv[i];
1033 		} else if (!strcmp(OPT_SIZE, argv[i])) {
1034 			g_merge_max_size = strtoul(argv[++i], NULL, 10);
1035 			if (g_merge_max_size % 512) {
1036 				printHelp();
1037 				return -1;
1038 			}
1039 			g_merge_max_size *= 1024; /* bytes */
1040 		} else {
1041 			optPath = argv[i];
1042 			break;
1043 		}
1044 	}
1045 	if (!merge && !optPath) {
1046 		fprintf(stderr, "need set out path to unpack!\n");
1047 		printHelp();
1048 		return -1;
1049 	}
1050 
1051 	gBuf = calloc(g_merge_max_size, 1);
1052 	if (!gBuf) {
1053 		LOGE("Merge image: calloc buffer error.\n");
1054 		return -1;
1055 	}
1056 
1057 	if (merge) {
1058 		LOGD("do_merge\n");
1059 		gConfigPath = optPath;
1060 		if (!mergeBoot(argc, argv)) {
1061 			fprintf(stderr, "merge failed!\n");
1062 			return -1;
1063 		}
1064 		printf("merge success(%s)\n", gOpts.outPath);
1065 	} else {
1066 		LOGD("do_unpack\n");
1067 		if (!unpackBoot(optPath)) {
1068 			fprintf(stderr, "unpack failed!\n");
1069 			return -1;
1070 		}
1071 		printf("unpack success\n");
1072 	}
1073 	return 0;
1074 }
1075