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