1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * 4 * Copyright (C) 2024 OpenWrt.org 5 * Copyright (C) 2024 Oleg S <remittor@gmail.com> 6 */ 7 8 #include <endian.h> 9 #include <errno.h> 10 #include <fcntl.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <stddef.h> 14 #include <stdint.h> 15 #include <string.h> 16 #include <stdarg.h> 17 #include <time.h> 18 #include <netinet/in.h> 19 #include <unistd.h> 20 #include <byteswap.h> 21 #include <zlib.h> /* crc32 */ 22 23 /* Various defines picked from U-boot */ 24 25 #define FDT_MAGIC 0xD00DFEED 26 27 #define IH_MAGIC 0x27051956 28 29 #define IH_OS_LINUX 5 30 31 #define IH_ARCH_ARM64 22 32 33 #define IH_TYPE_KERNEL 2 34 #define IH_TYPE_MULTI 4 35 36 #define IH_COMP_NONE 0 37 38 enum volume_t { 39 VOL_KERNEL = 0, 40 VOL_RAMDISK, 41 VOL_FLATDT, 42 43 VOL_COUNT, 44 }; 45 46 typedef struct { 47 uint8_t major; 48 uint8_t minor; 49 } __attribute__ ((packed)) version_t; 50 51 #define FS_OFFSET_PREFIX (0xA9) 52 53 typedef struct { 54 char prod_name[23]; 55 uint8_t unk0; // version of rootfs ??? 56 uint32_t fs_offset; // 24 bit BE (first byte = 0xA9) 57 } __attribute__ ((packed)) trx1_t; 58 59 typedef struct { 60 char prod_name[12]; 61 uint16_t sn; // fw build no (example: 388) 62 uint16_t en; // fw extended build no (example: 51234) 63 uint8_t dummy; // likely random byte 64 uint8_t key; // hash value from kernel and fs 65 uint8_t unk[6]; // likely random bytes 66 uint32_t fs_offset; // 24 bit BE (first byte = 0xA9) 67 } __attribute__ ((packed)) trx2_t; // hdr2 68 69 typedef struct { 70 char prod_name[23]; 71 uint8_t unk0; 72 uint32_t unk1; // ??? usualy: 0x003000 73 } __attribute__ ((packed)) trx3_t; 74 75 typedef struct image_header { 76 uint32_t ih_magic; 77 uint32_t ih_hcrc; 78 uint32_t ih_time; 79 uint32_t ih_size; // content size 80 uint32_t ih_load; // load addr 81 uint32_t ih_ep; // entry point 82 uint32_t ih_dcrc; // content hash 83 uint8_t ih_os; // os type 84 uint8_t ih_arch; // kernel arch 85 uint8_t ih_type; // image type 86 uint8_t ih_comp; // compression 87 version_t kernel_ver; // usualy: 3.0 88 version_t fs_ver; // usualy: 0.4 89 union { 90 trx1_t trx1; 91 trx2_t trx2; 92 trx3_t trx3; 93 } tail; 94 } __attribute__ ((packed)) image_header_t; 95 96 typedef struct { 97 uint32_t extendno; // fw extended build no (example: 51234) 98 uint16_t buildno; // fw build no (example: 388) 99 uint16_t r16; // always 0 ??? 100 uint32_t r32; // always 0 ??? 101 } __attribute__ ((packed)) tail_content_t; 102 103 #define DEF_ASUS_TAIL_MAGIC 0x2AFED414 104 105 typedef struct { 106 uint8_t flags: 4, // always 0 ??? 107 type : 4; // always 1 ??? 108 uint8_t clen[3]; // content len (24bit BE) 109 uint16_t fcrc; // crc for footer 110 uint16_t checksum; // content hash 111 uint32_t magic; 112 } __attribute__ ((packed)) tail_footer_t; 113 114 typedef struct { 115 int show_info; 116 char * imagefn; 117 char * outfn; 118 char prod_name[128]; 119 int trx_ver; 120 version_t kernel_ver; 121 version_t fs_ver; 122 uint32_t magic; 123 uint32_t type; 124 uint32_t flags; 125 uint32_t extendno; 126 uint32_t buildno; 127 uint32_t r16; 128 uint32_t r32; 129 } trx_opt_t; 130 131 trx_opt_t g_def = {0}; 132 trx_opt_t g_opt = {0}; 133 134 // ========================================================= 135 136 #define ROUNDUP(x, n) (((x) + (n - 1)) & ~(n - 1)) 137 138 // ========================================================= 139 140 char * g_progname = ""; 141 int g_debug = 0; 142 143 #define DBG(...) do { if (g_debug) printf(__VA_ARGS__); } while(0) 144 #define _attr_fmt_err_ __attribute__ ((format (printf, 1, 2))) 145 146 static _attr_fmt_err_ 147 void fatal_error(const char * fmtstr, ...) 148 { 149 va_list ap; 150 fflush(0); 151 fprintf(stderr, "%s: ERROR: ", g_progname); 152 va_start(ap, fmtstr); 153 vfprintf(stderr, fmtstr, ap); 154 va_end (ap); 155 fprintf(stderr, "\n"); 156 exit(EXIT_FAILURE); 157 } 158 159 #define ERR(fmtstr, ...) fatal_error(fmtstr, ## __VA_ARGS__) 160 161 static 162 uint16_t asus_hash16(const void * data, size_t length) 163 { 164 uint16_t * current = (uint16_t *) data; 165 length = length / sizeof(uint16_t); 166 uint16_t hash = 0; 167 168 while (length--) { 169 hash ^= *current++; 170 } 171 return ~hash; // same as hash ^ 0xFFFF 172 } 173 174 void update_iheader_crc(image_header_t * hdr, const void * data, size_t data_size) 175 { 176 if (data == NULL) 177 data = (const void *)((char *)hdr + sizeof(image_header_t)); 178 179 // Calculate payload checksum 180 hdr->ih_dcrc = htobe32(crc32(0, data, data_size)); 181 hdr->ih_size = htobe32(data_size); 182 183 // Calculate header checksum 184 hdr->ih_hcrc = 0; 185 hdr->ih_hcrc = htobe32(crc32(0, (const void *)hdr, sizeof(image_header_t))); 186 } 187 188 static 189 void init_opt(void) 190 { 191 memset(&g_def, 0, sizeof(g_def)); 192 g_def.show_info = 0; 193 g_def.trx_ver = 3; 194 g_def.magic = DEF_ASUS_TAIL_MAGIC; 195 g_def.type = 1; 196 g_def.flags = 0; 197 memcpy(&g_opt, &g_def, sizeof(g_def)); 198 } 199 200 static 201 void usage(int status) 202 { 203 FILE * fp = (status != EXIT_SUCCESS) ? stderr : stdout; 204 205 fprintf(fp, "Usage: %s -i <image> [OPTIONS...]\n", g_progname); 206 fprintf(fp, "\n"); 207 fprintf(fp, "Options:\n"); 208 fprintf(fp, " -i <filename> input image filename \n"); 209 fprintf(fp, " -o <filename> output image filename \n"); 210 fprintf(fp, " -x show only image info \n"); 211 fprintf(fp, " -n <name> product name \n"); 212 fprintf(fp, " -v <number> TRX version: 2 or 3 (def: %d) \n", g_def.trx_ver); 213 fprintf(fp, " -K <#>.<#> kernel version (def: \"%d.%d\") \n", g_def.kernel_ver.major, g_def.kernel_ver.minor); 214 fprintf(fp, " -F <#>.<#> filesys version (def: \"%d.%d\") \n", g_def.fs_ver.major, g_def.fs_ver.minor); 215 fprintf(fp, " -m <signature> tail HEX signature (def: %08X) \n", g_def.magic); 216 fprintf(fp, " -t <number> tail type (def: %X) \n", g_def.type); 217 fprintf(fp, " -f <number> tail flags (def: %X) \n", g_def.flags); 218 fprintf(fp, " -e <number> tail ext no (def: %u) \n", g_def.extendno); 219 fprintf(fp, " -b <number> tail build no (def: %u) \n", g_def.buildno); 220 fprintf(fp, " -h show this screen \n"); 221 exit(status); 222 } 223 224 static 225 int parse_args(int argc, char ** argv) 226 { 227 char *str, *end; 228 int opt; 229 230 while ((opt = getopt(argc, argv, "Dxi:o:n:K:F:v:m:t:f:e:b:h?")) != -1) { 231 switch (opt) { 232 case 'i': 233 g_opt.imagefn = optarg; 234 break; 235 case 'o': 236 g_opt.outfn = optarg; 237 break; 238 case 'x': 239 g_opt.show_info = 1; 240 g_debug = 1; 241 break; 242 case 'D': 243 g_debug = 1; 244 break; 245 case 'n': 246 strncpy(g_opt.prod_name, optarg, sizeof(g_opt.prod_name) - 1); 247 break; 248 case 'v': 249 g_opt.trx_ver = strtoul(optarg, &end, 0); 250 if (end == optarg) 251 ERR("Incorrect -v argument!"); 252 break; 253 case 'K': 254 g_opt.kernel_ver.major = (uint8_t) strtoul(optarg, &end, 10); 255 if (end == optarg || end[0] != '.') 256 ERR("Incorrect -K argument!"); 257 258 str = end + 1; 259 g_opt.kernel_ver.minor = (uint8_t) strtoul(str, &end, 10); 260 if (end == str) 261 ERR("Incorrect -K argument!"); 262 break; 263 case 'F': 264 g_opt.fs_ver.major = (uint8_t) strtoul(optarg, &end, 10); 265 if (end == optarg || end[0] != '.') 266 ERR("Incorrect -F argument!"); 267 268 str = end + 1; 269 g_opt.fs_ver.minor = (uint8_t) strtoul(str, &end, 10); 270 if (end == str) 271 ERR("Incorrect -F argument!"); 272 break; 273 case 'm': 274 g_opt.magic = strtoul(optarg, &end, 16); 275 if (end == optarg) 276 ERR("Incorrect -m argument!"); 277 break; 278 case 't': 279 g_opt.type = strtoul(optarg, &end, 0); 280 if (end == optarg) 281 ERR("Incorrect -t argument!"); 282 break; 283 case 'f': 284 g_opt.flags = strtoul(optarg, &end, 0); 285 if (end == optarg) 286 ERR("Incorrect -f argument!"); 287 break; 288 case 'e': 289 g_opt.extendno = strtoul(optarg, &end, 0); 290 if (end == optarg) 291 ERR("Incorrect -e argument!"); 292 break; 293 case 'b': 294 g_opt.buildno = strtoul(optarg, &end, 0); 295 if (end == optarg) 296 ERR("Incorrect -b argument!"); 297 break; 298 case 'h': 299 default: 300 usage(EXIT_FAILURE); 301 } 302 } 303 if (g_opt.imagefn == NULL || g_opt.imagefn[0] == 0) 304 usage(EXIT_FAILURE); // Required input image filename! 305 306 if (g_opt.show_info == 0) 307 if (g_opt.outfn == NULL || g_opt.outfn[0] == 0) 308 usage(EXIT_FAILURE); // Required output image filename! 309 310 if (g_opt.trx_ver < 2 || g_opt.trx_ver > 3) 311 usage(EXIT_FAILURE); 312 313 return 0; 314 } 315 316 static 317 char * load_image(size_t pad_size, size_t * psize) 318 { 319 uint32_t file_sz; 320 size_t readed; 321 void * buf; 322 FILE *fp; 323 324 fp = fopen(g_opt.imagefn, "rb"); 325 if (!fp) 326 ERR("Can't open %s: %s", g_opt.imagefn, strerror(errno)); 327 328 rewind(fp); 329 fseek(fp, 0, SEEK_END); 330 file_sz = ftell(fp); 331 rewind(fp); 332 333 if ((int32_t)file_sz <= 0) { 334 fclose(fp); 335 ERR("Error getting filesize: %s", g_opt.imagefn); 336 } 337 338 if (file_sz <= sizeof(image_header_t)) { 339 fclose(fp); 340 ERR("Bad size: \"%s\" is no valid image", g_opt.imagefn); 341 } 342 343 buf = malloc(file_sz + pad_size); 344 if (!buf) { 345 fclose(fp); 346 ERR("Out of memory!"); 347 } 348 memset(buf, 0, file_sz + pad_size); 349 350 readed = fread(buf, 1, file_sz, fp); 351 fclose(fp); 352 if (readed != (size_t)file_sz) 353 ERR("Error reading file %s", g_opt.imagefn); 354 355 *psize = file_sz; 356 357 return (char *)buf; 358 } 359 360 static 361 uint32_t get_timestamp(void) 362 { 363 char * env = getenv("SOURCE_DATE_EPOCH"); 364 time_t fixed_timestamp = -1; 365 char * endptr = env; 366 367 if (env && *env) { 368 errno = 0; 369 fixed_timestamp = (time_t) strtoull(env, &endptr, 10); 370 371 if (errno || (endptr && *endptr != '\0')) { 372 fprintf(stderr, "ERROR: Invalid SOURCE_DATE_EPOCH \n"); 373 fixed_timestamp = -1; 374 } 375 } 376 377 if (fixed_timestamp == -1) 378 time(&fixed_timestamp); 379 380 DBG("timestamp: %u \n", (uint32_t)fixed_timestamp); 381 return (uint32_t)fixed_timestamp; 382 } 383 384 static int show_info(char *img, size_t img_size) 385 { 386 uint32_t data_size, fdt_size, fs_size, fs_offset = 0; 387 uint16_t fcrc, fcrc_c, checksum_c; 388 uint8_t fs_key, kernel_key, key; 389 uint32_t sn, en, xx = 0; 390 size_t buf_size = 12; 391 tail_footer_t * foot; 392 tail_content_t *cont; 393 image_header_t *hdr; 394 uint32_t cont_len; 395 uint32_t *fs_data; 396 uint8_t *buf; 397 trx2_t *trx; 398 int i; 399 400 /* Assume valid, already validated early in process_image */ 401 hdr = (image_header_t *)img; 402 foot = (tail_footer_t *)(img + img_size - sizeof(tail_footer_t)); 403 404 if (be32toh(hdr->ih_magic) != IH_MAGIC) { 405 free(img); 406 ERR("Incorrect image: \"%s\" magic must be %08X", g_opt.imagefn, IH_MAGIC); 407 } 408 409 g_opt.trx_ver = 0; 410 if (be32toh(foot->magic) == g_opt.magic) 411 g_opt.trx_ver = 3; /* tail with magic = DEF_ASUS_TAIL_MAGIC */ 412 413 if (be32toh(hdr->tail.trx2.fs_offset) >> 24 == FS_OFFSET_PREFIX) { 414 g_opt.trx_ver = 1; /* hdr1 */ 415 416 for (i = 0; i < sizeof(hdr->tail.trx1.prod_name); i++) { 417 if (hdr->tail.trx1.prod_name[i] >= 0x7F) 418 g_opt.trx_ver = 2; /* hdr2 */ 419 } 420 421 if (hdr->tail.trx2.sn >= 380 && hdr->tail.trx2.sn <= 490) 422 g_opt.trx_ver = 2; /* hdr2 */ 423 } 424 425 DBG("detect trx version = %d \n", g_opt.trx_ver); 426 switch(g_opt.trx_ver) { 427 case 1: 428 free(img); 429 ERR("Formart HDR1 currently not supported"); 430 break; 431 case 2: 432 trx = &hdr->tail.trx2; 433 434 data_size = (uint32_t)be32toh(hdr->ih_size); 435 sn = htole16(trx->sn); 436 en = htole16(trx->en); 437 438 if (en < 20000 && sn >= 386) 439 en += 0x10000; 440 441 DBG("hdr2.sn: %u (0x%04X) \n", sn, sn); 442 DBG("hdr2.en: %u (0x%04X) \n", en, htole16(trx->en)); 443 DBG("hdr2.key: 0x%02X \n", trx->key); 444 buf = trx->unk; 445 for (size_t i = 0; i < buf_size; i += 2) { 446 if (buf[0] == FS_OFFSET_PREFIX && (buf[3] & 3) == 0) { 447 xx = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | (xx && 0xFF); 448 fs_offset = be32toh(xx); 449 buf += 2; 450 } 451 buf += 2; 452 } 453 DBG("fs_offset: 0x%08X \n", fs_offset); 454 if (fs_offset + 128 > img_size) 455 ERR("Incorrect fs_offset!"); 456 457 fs_data = (uint32_t *)(img + fs_offset); 458 DBG("fs_data: %08X %08X \n", be32toh(fs_data[0]), be32toh(fs_data[1])); 459 fs_size = sizeof(image_header_t) + data_size - fs_offset; 460 DBG("fs_size: 0x%X bytes \n", fs_size); 461 fs_key = img[fs_offset + fs_size / 2]; 462 kernel_key = img[fs_offset / 2]; 463 DBG("fs_key: 0x%02X kernel_key: 0x%02X \n", fs_key, kernel_key); 464 if (fs_key) { 465 key = kernel_key + ~fs_key; 466 } else { 467 key = (kernel_key % 3) - 3; 468 } 469 DBG("key = 0x%02X \n", key); 470 if (be32toh(fs_data[0]) == FDT_MAGIC) { 471 DBG("fdt_offset: 0x%08X \n", fs_offset); 472 fdt_size = be32toh(fs_data[1]); 473 DBG("fdt_size: 0x%X bytes \n", fdt_size); 474 fs_offset += ROUNDUP(fdt_size, 64); 475 DBG("fs_offset: 0x%08X \n", fs_offset); 476 fs_size -= ROUNDUP(fdt_size, 64); 477 DBG("fs_size: 0x%X bytes \n", fs_size); 478 } 479 break; 480 case 3: 481 DBG("tail: footer size = 0x%lX (%lu) \n", sizeof(tail_footer_t), sizeof(tail_footer_t)); 482 DBG("tail: footer magic: 0x%X \n", be32toh(foot->magic)); 483 484 cont_len = foot->clen[0] << 24 | foot->clen[1] << 16 | foot->clen[2]; 485 DBG("tail: type = %X, flags = %X, content len = 0x%06X \n", foot->type, foot->flags, cont_len); 486 487 fcrc = foot->fcrc; 488 foot->fcrc = 0; 489 fcrc_c = asus_hash16(foot, sizeof(*foot)); 490 DBG("tail: fcrc = %04X (%04X) \n", be16toh(fcrc), fcrc_c); 491 492 cont = (tail_content_t *)((char *)foot - cont_len); 493 checksum_c = asus_hash16(cont, sizeof(*cont)); 494 DBG("cont: checksum = %04X (%04X) \n", be16toh(foot->checksum), checksum_c); 495 496 DBG("cont: buildno: %u, extendno: %u \n", be16toh(cont->buildno), be32toh(cont->extendno)); 497 DBG("cont: r16: 0x%08X, r32: 0x%08X \n", be16toh(cont->r16), be32toh(cont->r32)); 498 break; 499 default: 500 free(img); 501 ERR("Input image is not compatible with AsusWRT"); 502 } 503 504 free(img); 505 return 0; 506 } 507 508 static 509 int process_image(void) 510 { 511 const uint32_t hsz = sizeof(image_header_t); 512 uint32_t vol_offset[VOL_COUNT + 1] = { 0 }; 513 uint32_t i, data_size, data_crc_c, fs_offset = 0, vol_count = 0, 514 *fs_data, fs_size, fdt_size, *vol_size, xoffset, *fdt, 515 cur_fdt_offset, new_fdt_offset, new_fs_offset, pad, 516 hsqs_offset, hsqs_size, *hsqs_data, cont_len; 517 uint32_t __attribute__ ((unused)) fdt_offset; 518 size_t img_size = 0, max_prod_len, new_img_size, 519 new_data_size, wlen; 520 char *img, *img_end, *prod_name; 521 uint8_t fs_key, kernel_key, key; 522 const char *prod_name_str; 523 tail_content_t *cont; 524 image_header_t *hdr; 525 tail_footer_t *foot; 526 trx2_t *trx; 527 FILE *fp; 528 529 img = load_image(1024, &img_size); 530 if (!img) 531 ERR("Can't load file %s", g_opt.imagefn); 532 533 if (g_opt.show_info) 534 return show_info(img, img_size); 535 536 hdr = (image_header_t *)img; 537 if (be32toh(hdr->ih_magic) != IH_MAGIC) { 538 memmove(img + hsz, img, img_size); 539 memset(hdr, 0, hsz); 540 hdr->ih_magic = htobe32(IH_MAGIC); 541 hdr->ih_time = htobe32(get_timestamp()); 542 hdr->ih_size = htobe32(img_size); 543 hdr->ih_load = 0; 544 hdr->ih_ep = 0; 545 hdr->ih_os = IH_OS_LINUX; 546 hdr->ih_arch = IH_ARCH_ARM64; 547 hdr->ih_type = IH_TYPE_KERNEL; 548 hdr->ih_comp = IH_COMP_NONE; 549 img_size += hsz; 550 } 551 data_size = (uint32_t)be32toh(hdr->ih_size); 552 DBG("data: size = 0x%08X (%u bytes) \n", data_size, data_size); 553 if (data_size + hsz > img_size) 554 ERR("Bad size: \"%s\" is no valid content size", g_opt.imagefn); 555 556 data_crc_c = crc32(0, (const unsigned char *)(img + hsz), data_size); 557 DBG("data: crc = %08X (%08X) \n", be32toh(hdr->ih_dcrc), data_crc_c); 558 559 DBG("image type: %d \n", (int)hdr->ih_type); 560 561 img_end = img + img_size; 562 563 memset(&hdr->tail.trx1, 0, sizeof(hdr->tail.trx1)); 564 switch(g_opt.trx_ver) { 565 case 2: 566 prod_name = hdr->tail.trx2.prod_name; 567 max_prod_len = sizeof(hdr->tail.trx2.prod_name); 568 break; 569 case 3: 570 prod_name = hdr->tail.trx3.prod_name; 571 max_prod_len = sizeof(hdr->tail.trx3.prod_name); 572 } 573 574 prod_name_str = (const char *)&hdr->kernel_ver; 575 if (g_opt.prod_name[0]) 576 prod_name_str = g_opt.prod_name; 577 578 strncpy(prod_name, prod_name_str, max_prod_len); 579 hdr->kernel_ver = g_opt.kernel_ver; 580 hdr->fs_ver = g_opt.fs_ver; 581 582 switch(g_opt.trx_ver) { 583 case 2: 584 trx = &hdr->tail.trx2; 585 586 if (hdr->ih_type == IH_TYPE_MULTI) { 587 DBG("detect image with type: IH_TYPE_MULTI \n"); 588 vol_size = (uint32_t *)(img + hsz); 589 if (vol_size[0] == 0) { 590 free(img); 591 ERR("Multi image does not contain volumes"); 592 } 593 594 for (uint32_t i = 0; i <= VOL_COUNT; i++) { 595 if (vol_size[i] == 0) 596 break; 597 vol_count++; 598 } 599 DBG("Multi image: volumes count = %u \n", vol_count); 600 601 if (vol_count > VOL_COUNT) { 602 free(img); 603 ERR("Multi image contains too many volumes"); 604 } 605 606 xoffset = hsz + sizeof(uint32_t) * (vol_count + 1); 607 for (i = 0; i < vol_count; i++) { 608 xoffset = ROUNDUP(xoffset, 4); 609 vol_offset[i] = xoffset; 610 DBG("Multi image: volume %u has offset = 0x%08X \n", i, xoffset); 611 if (be32toh(vol_size[i]) > 0x4FFFFFF) { 612 free(img); 613 ERR("Multi image contain volume %u with huge size", i); 614 } 615 616 xoffset += be32toh(vol_size[i]); 617 } 618 if (xoffset > img_size) { 619 free(img); 620 ERR("Multi image contain incorrect img-size header"); 621 } 622 623 fdt = (uint32_t *)(img + vol_offset[VOL_FLATDT]); 624 if (vol_offset[VOL_FLATDT] && be32toh(fdt[0]) == FDT_MAGIC) { 625 if (hdr->ih_arch == IH_ARCH_ARM64 && (vol_offset[VOL_FLATDT] & 7) != 0) { 626 // for ARM64 offset of FlatDT must be 8-bytes align 627 cur_fdt_offset = vol_offset[VOL_FLATDT]; 628 new_fdt_offset = vol_offset[VOL_FLATDT] + 4; 629 memmove(img + new_fdt_offset, img + cur_fdt_offset, img_size - cur_fdt_offset); 630 memset(img + cur_fdt_offset, 0, 4); 631 img_size += 4; 632 data_size += 4; 633 vol_offset[VOL_FLATDT] = new_fdt_offset; 634 vol_size[VOL_RAMDISK] = htobe32( be32toh(vol_size[VOL_RAMDISK]) + 4 ); 635 DBG("Multi image: volume %u size increased by 4 bytes \n", VOL_RAMDISK); 636 DBG("Multi image: volume %u has offset = 0x%08X (patched) \n", VOL_FLATDT, new_fdt_offset); 637 } 638 } 639 fs_offset = vol_offset[VOL_RAMDISK]; 640 if (fs_offset == 0) { 641 //ERR("Multi image does not contain rootfs volume"); 642 fs_offset = hsz + data_size; 643 } 644 } else { 645 fs_offset = hsz + data_size; 646 if (fs_offset & 3) { 647 //ERR("kernel size must be align to 4 bytes"); 648 new_fs_offset = ROUNDUP(fs_offset, 4); 649 memmove(img + new_fs_offset, img + fs_offset, img_size - fs_offset); 650 pad = new_fs_offset - fs_offset; 651 memset(img + fs_offset, 0, pad); 652 img_size += pad; 653 data_size += pad; 654 fs_offset = new_fs_offset; 655 } 656 } 657 DBG("fs_offset: 0x%08X \n", fs_offset); 658 fs_data = (uint32_t *)(img + fs_offset); 659 DBG("fs_data: %08X %08X \n", be32toh(fs_data[0]), be32toh(fs_data[1])); 660 fs_size = img_size - fs_offset; 661 fdt_offset = 0; 662 fdt_size = 0; 663 hsqs_offset = fs_offset; 664 hsqs_size = fs_size; 665 if (be32toh(fs_data[0]) == FDT_MAGIC && !vol_count) { 666 fdt_offset = fs_offset; 667 DBG("fdt_offset: 0x%08X \n", fs_offset); 668 fdt_size = be32toh(fs_data[1]); 669 DBG("fdt_size: 0x%X bytes \n", fdt_size); 670 hsqs_offset += ROUNDUP(fdt_size, 64); 671 hsqs_size -= ROUNDUP(fdt_size, 64); 672 } 673 DBG("hsqs_offset: 0x%08X \n", hsqs_offset); 674 DBG("hsqs_size: 0x%X bytes \n", hsqs_size); 675 hsqs_data = (uint32_t *)(img + hsqs_offset); 676 DBG("hsqs_data: %08X %08X \n", be32toh(hsqs_data[0]), be32toh(hsqs_data[1])); 677 kernel_key = img[fs_offset / 2]; 678 fs_key = img[fs_offset + fs_size / 2]; 679 DBG("fs_key: 0x%02X kernel_key: 0x%02X \n", fs_key, kernel_key); 680 key = fs_key ? kernel_key + ~fs_key : (kernel_key % 3) - 3; 681 DBG("key = 0x%02X \n", key); 682 trx->sn = htole16((uint16_t)g_opt.buildno); 683 trx->en = htole16((uint16_t)g_opt.extendno); 684 trx->key = key; 685 if (fs_offset >= 0xFFFFFF) { 686 free(img); 687 ERR("kernel image size is too big (max size: 16MiB)"); 688 } 689 690 trx->fs_offset = htobe32((FS_OFFSET_PREFIX << 24) + fs_offset); 691 update_iheader_crc(hdr, NULL, img_size - hsz); 692 break; 693 case 3: 694 cont_len = 0; 695 cont = NULL; 696 foot = NULL; 697 698 hdr->tail.trx3.unk1 = htobe32(0x3000); // unknown value 699 700 cont_len = img_size - hsz - data_size + sizeof(tail_content_t); 701 cont = (tail_content_t *)img_end; 702 cont->extendno = htobe32(g_opt.extendno); 703 cont->buildno = htobe16(g_opt.buildno); 704 cont->r16 = htobe16(g_opt.r16); 705 cont->r32 = htobe32(g_opt.r32); 706 707 foot = (tail_footer_t *)(img_end + sizeof(tail_content_t)); 708 char * cont_ptr = img + hsz + data_size; 709 foot->checksum = htobe16(asus_hash16(cont_ptr, cont_len)); 710 711 if (cont_len >= (1UL << 24)) { 712 free(img); 713 ERR("Content length is too long (more than 0x%lX bytes)", 1UL << 24); 714 } 715 716 foot->clen[0] = (cont_len >> 16) & 0xFF; // 24bit BigEndian 717 foot->clen[1] = (cont_len >> 8) & 0xFF; 718 foot->clen[2] = cont_len & 0xFF; 719 720 foot->magic = htobe32(g_opt.magic); 721 foot->type = g_opt.type; 722 foot->flags = g_opt.flags; 723 foot->fcrc = 0; 724 foot->fcrc = htobe16(asus_hash16(foot, sizeof(*foot))); 725 726 new_img_size = (size_t)((char *)foot + sizeof(tail_footer_t) - img); 727 new_data_size = new_img_size - hsz; 728 update_iheader_crc(hdr, NULL, new_data_size); 729 730 img_size = hsz + data_size + cont_len + sizeof(tail_footer_t); 731 } 732 733 fp = fopen(g_opt.outfn, "wb"); 734 if (!fp) { 735 free(img); 736 ERR("Can't open %s for writing: %s", g_opt.outfn, strerror(errno)); 737 } 738 739 wlen = fwrite(img, img_size, 1, fp); 740 fclose(fp); 741 if (wlen != 1) { 742 free(img); 743 ERR("Failed to write: %s", g_opt.outfn); 744 } 745 746 DBG("New TRX-image file created: \"%s\" \n", g_opt.outfn); 747 free(img); 748 749 return 0; // OK 750 } 751 752 int main(int argc, char ** argv) 753 { 754 g_progname = argv[0]; 755 756 init_opt(); 757 parse_args(argc, argv); 758 759 int rc = process_image(); 760 761 return rc; 762 } 763
This page was automatically generated by LXR 0.3.1. • OpenWrt