1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * mkdlinkfw 4 * 5 * Copyright (C) 2018 Paweł Dembicki <paweldembicki@gmail.com> 6 * 7 * This tool is based on mktplinkfw. 8 * Copyright (C) 2009 Gabor Juhos <juhosg@openwrt.org> 9 * Copyright (C) 2008,2009 Wang Jian <lark@linux.net.cn> 10 */ 11 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <stdint.h> 15 #include <string.h> 16 #include <unistd.h> /* for unlink() */ 17 #include <libgen.h> 18 #include <getopt.h> /* for getopt() */ 19 #include <stdarg.h> 20 #include <stdbool.h> 21 #include <endian.h> 22 #include <errno.h> 23 #include <sys/stat.h> 24 #include <zlib.h> /*for crc32 */ 25 26 #include "mkdlinkfw-lib.h" 27 28 /* ARM update header 2.0 29 * used only in factory images to erase and flash selected area 30 */ 31 struct auh_header { 32 uint8_t rom_id[12]; /* 12-bit rom-id unique per router type */ 33 uint16_t derange; /* used for scramble header */ 34 uint16_t image_checksum; /* jboot_checksum of flashed data */ 35 36 uint32_t space1; /* zeros */ 37 uint32_t space2; /* zeros */ 38 uint16_t space3; /* zerosu */ 39 uint8_t lpvs; /* must be 0x01 */ 40 uint8_t mbz; /* bust be 0 */ 41 uint32_t time_stamp; /* timestamp calculated in jboot way */ 42 43 uint32_t erase_start; /* erase start address */ 44 uint32_t erase_length; /* erase length address */ 45 uint32_t data_offset; /* data start address */ 46 uint32_t data_length; /* data length address */ 47 48 uint32_t space4; /* zeros */ 49 uint32_t space5; /* zeros */ 50 uint32_t space6; /* zeros */ 51 uint32_t space7; /* zeros */ 52 53 uint16_t header_id; /* magic 0x4842 */ 54 uint16_t header_version; /* 0x02 for 2.0 */ 55 uint16_t space8; /* zeros */ 56 uint8_t section_id; /* section id */ 57 uint8_t image_info_type; /* (?) 0x04 in factory images */ 58 uint32_t image_info_offset; /* (?) zeros in factory images */ 59 uint16_t family_member; /* unique per router type */ 60 uint16_t header_checksum; /* negated jboot_checksum of header data */ 61 }; 62 63 struct stag_header { /* used only of sch2 wrapped kernel data */ 64 uint8_t cmark; /* in factory 0xFF ,in sysuograde must be the same as id */ 65 uint8_t id; /* 0x04 */ 66 uint16_t magic; /* magic 0x2B24 */ 67 uint32_t time_stamp; /* timestamp calculated in jboot way */ 68 uint32_t image_length; /* lentgh of kernel + sch2 header */ 69 uint16_t image_checksum; /* negated jboot_checksum of sch2 + kernel */ 70 uint16_t tag_checksum; /* negated jboot_checksum of stag header data */ 71 }; 72 73 struct sch2_header { /* used only in kernel partitions */ 74 uint16_t magic; /* magic 0x2124 */ 75 uint8_t cp_type; /* 0x00 for flat, 0x01 for jz, 0x02 for gzip, 0x03 for lzma */ 76 uint8_t version; /* 0x02 for sch2 */ 77 uint32_t ram_addr; /* ram entry address */ 78 uint32_t image_len; /* kernel image length */ 79 uint32_t image_crc32; /* kernel image crc */ 80 uint32_t start_addr; /* ram start address */ 81 uint32_t rootfs_addr; /* rootfs flash address */ 82 uint32_t rootfs_len; /* rootfls length */ 83 uint32_t rootfs_crc32; /* rootfs crc32 */ 84 uint32_t header_crc32; /* sch2 header crc32, durring calculation this area is replaced by zero */ 85 uint16_t header_length; /* sch2 header length: 0x28 */ 86 uint16_t cmd_line_length; /* cmd line length, known zeros */ 87 }; 88 89 /* globals */ 90 static struct file_info inspect_info; 91 struct file_info kernel_info; 92 struct file_info rootfs_info; 93 struct file_info image_info; 94 95 char *ofname; 96 char *progname; 97 uint32_t firmware_size; 98 uint32_t image_offset; 99 uint16_t family_member; 100 char *rom_id[12] = { 0 }; 101 char image_type; 102 103 static void usage(int status) 104 { 105 fprintf(stderr, "Usage: %s [OPTIONS...]\n", progname); 106 fprintf(stderr, 107 "\n" 108 "Options:\n" 109 " -i <file> inspect given firmware file <file>\n" 110 " -f set family member id (hexval prefixed with 0x)\n" 111 " -F <file> read image and convert it to FACTORY\n" 112 " -k <file> read kernel image from the file <file>\n" 113 " -r <file> read rootfs image from the file <file>\n" 114 " -o <file> write output to the file <file>\n" 115 " -s <size> set firmware partition size\n" 116 " -m <version> set rom id to <version> (12-bit string val: \"DLK*********\")\n" 117 " -h show this screen\n"); 118 119 exit(status); 120 } 121 122 void print_auh_header(struct auh_header *printed_header) 123 { 124 printf("\trom_id: %s\n" 125 "\tderange: 0x%04X\n" 126 "\timage_checksum: 0x%04X\n" 127 "\tspace1: 0x%08X\n" 128 "\tspace2: 0x%08X\n" 129 "\tspace3: 0x%04X\n" 130 "\tlpvs: 0x%02X\n" 131 "\tmbz: 0x%02X\n" 132 "\ttime_stamp: 0x%08X\n" 133 "\terase_start: 0x%08X\n" 134 "\terase_length: 0x%08X\n" 135 "\tdata_offset: 0x%08X\n" 136 "\tdata_length: 0x%08X\n" 137 "\tspace4: 0x%08X\n" 138 "\tspace5: 0x%08X\n" 139 "\tspace6: 0x%08X\n" 140 "\tspace7: 0x%08X\n" 141 "\theader_id: 0x%04X\n" 142 "\theader_version: 0x%02X\n" 143 "\tspace8: 0x%04X\n" 144 "\tsection_id: 0x%02X\n" 145 "\timage_info_type: 0x%02X\n" 146 "\timage_info_offset 0x%08X\n" 147 "\tfamily_member: 0x%04X\n" 148 "\theader_checksum: 0x%04X\n", 149 printed_header->rom_id, 150 printed_header->derange, 151 printed_header->image_checksum, 152 printed_header->space1, 153 printed_header->space2, 154 printed_header->space3, 155 printed_header->lpvs, 156 printed_header->mbz, 157 printed_header->time_stamp, 158 printed_header->erase_start, 159 printed_header->erase_length, 160 printed_header->data_offset, 161 printed_header->data_length, 162 printed_header->space4, 163 printed_header->space5, 164 printed_header->space6, 165 printed_header->space7, 166 printed_header->header_id, 167 printed_header->header_version, 168 printed_header->space8, 169 printed_header->section_id, 170 printed_header->image_info_type, 171 printed_header->image_info_offset, 172 printed_header->family_member, printed_header->header_checksum); 173 } 174 175 void print_stag_header(struct stag_header *printed_header) 176 { 177 printf("\tcmark: 0x%02X\n" 178 "\tid: 0x%02X\n" 179 "\tmagic: 0x%04X\n" 180 "\ttime_stamp: 0x%08X\n" 181 "\timage_length: 0x%04X\n" 182 "\timage_checksum: 0x%04X\n" 183 "\ttag_checksum: 0x%04X\n", 184 printed_header->cmark, 185 printed_header->id, 186 printed_header->magic, 187 printed_header->time_stamp, 188 printed_header->image_length, 189 printed_header->image_checksum, printed_header->tag_checksum); 190 } 191 192 void print_sch2_header(struct sch2_header *printed_header) 193 { 194 printf("\tmagic: 0x%04X\n" 195 "\tcp_type: 0x%02X\n" 196 "\tversion: 0x%02X\n" 197 "\tram_addr: 0x%08X\n" 198 "\timage_len: 0x%08X\n" 199 "\timage_crc32: 0x%08X\n" 200 "\tstart_addr: 0x%08X\n" 201 "\trootfs_addr: 0x%08X\n" 202 "\trootfs_len: 0x%08X\n" 203 "\trootfs_crc32: 0x%08X\n" 204 "\theader_crc32: 0x%08X\n" 205 "\theader_length: 0x%04X\n" 206 "\tcmd_line_length: 0x%04X\n", 207 printed_header->magic, 208 printed_header->cp_type, 209 printed_header->version, 210 printed_header->ram_addr, 211 printed_header->image_len, 212 printed_header->image_crc32, 213 printed_header->start_addr, 214 printed_header->rootfs_addr, 215 printed_header->rootfs_len, 216 printed_header->rootfs_crc32, 217 printed_header->header_crc32, 218 printed_header->header_length, printed_header->cmd_line_length); 219 } 220 221 static int find_auh_headers(char *buf) 222 { 223 char *tmp_buf = buf; 224 struct auh_header *tmp_header[MAX_HEADER_COUNTER]; 225 int header_counter = 0; 226 227 int ret = EXIT_FAILURE; 228 229 while (tmp_buf - buf <= inspect_info.file_size - AUH_SIZE) { 230 if (!memcmp(tmp_buf, AUH_MAGIC, 3)) { 231 if (((struct auh_header *)tmp_buf)->header_checksum == 232 (uint16_t) ~jboot_checksum(0, (uint16_t *) tmp_buf, 233 AUH_SIZE - 2)) { 234 uint16_t checksum = 0; 235 printf("Find proper AUH header at: 0x%lX!\n", 236 tmp_buf - buf); 237 tmp_header[header_counter] = 238 (struct auh_header *)tmp_buf; 239 checksum = 240 jboot_checksum(0, (uint16_t *) ((char *) 241 tmp_header 242 [header_counter] 243 + AUH_SIZE), 244 tmp_header 245 [header_counter]->data_length); 246 if (tmp_header[header_counter]->image_checksum 247 == checksum) 248 printf("Image checksum ok.\n"); 249 else 250 ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", tmp_header[header_counter]->image_checksum, checksum); 251 header_counter++; 252 if (header_counter > MAX_HEADER_COUNTER) 253 break; 254 } 255 } 256 tmp_buf++; 257 } 258 259 if (header_counter == 0) 260 ERR("Can't find proper AUH header!\n"); 261 else if (header_counter > MAX_HEADER_COUNTER) 262 ERR("To many AUH headers!\n"); 263 else { 264 for (int i = 0; i < header_counter; i++) { 265 printf("AUH %d:\n", i); 266 print_auh_header(tmp_header[i]); 267 } 268 269 ret = EXIT_SUCCESS; 270 } 271 272 return ret; 273 } 274 275 static int check_stag_header(char *buf, struct stag_header *header) 276 { 277 278 int ret = EXIT_FAILURE; 279 280 uint8_t cmark_tmp = header->cmark; 281 header->cmark = header->id; 282 283 if (header->tag_checksum == 284 (uint16_t) ~jboot_checksum(0, (uint16_t *) header, 285 STAG_SIZE - 2)) { 286 uint16_t checksum = 0; 287 printf("Find proper STAG header at: 0x%lX!\n", 288 (char *)header - buf); 289 checksum = 290 jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE), 291 header->image_length); 292 if (header->image_checksum == checksum) { 293 printf("Image checksum ok.\n"); 294 header->cmark = cmark_tmp; 295 print_stag_header(header); 296 ret = EXIT_SUCCESS; 297 } else 298 ERR("Image checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_checksum, checksum); 299 } else 300 ERR("STAG header checksum incorrect!"); 301 302 header->cmark = cmark_tmp; 303 return ret; 304 } 305 306 static int check_sch2_header(char *buf, struct sch2_header *header) 307 { 308 309 int ret = EXIT_FAILURE; 310 311 uint32_t crc32_tmp = header->header_crc32; 312 header->header_crc32 = 0; 313 314 if (crc32_tmp == crc32(0, (uint8_t *) header, header->header_length)) { 315 uint32_t crc32_val; 316 printf("Find proper SCH2 header at: 0x%lX!\n", 317 (char *)header - buf); 318 319 crc32_val = 320 crc32(0, (uint8_t *) header + header->header_length, 321 header->image_len); 322 if (header->image_crc32 == crc32_val) { 323 printf("Kernel checksum ok.\n"); 324 325 header->header_crc32 = crc32_tmp; 326 print_sch2_header(header); 327 ret = EXIT_SUCCESS; 328 } else 329 ERR("Kernel checksum incorrect! Stored: 0x%X Calculated: 0x%X\n", header->image_crc32, crc32_val); 330 331 } else 332 ERR("SCH2 header checksum incorrect!"); 333 334 header->header_crc32 = crc32_tmp; 335 return ret; 336 } 337 338 static int inspect_fw(void) 339 { 340 char *buf; 341 struct stag_header *stag_header_kernel; 342 struct sch2_header *sch2_header_kernel; 343 int ret = EXIT_FAILURE; 344 345 buf = malloc(inspect_info.file_size); 346 if (!buf) { 347 ERR("no memory for buffer!\n"); 348 goto out; 349 } 350 351 ret = read_to_buf(&inspect_info, buf); 352 if (ret) 353 goto out_free_buf; 354 355 ret = find_auh_headers(buf); 356 if (ret) 357 goto out_free_buf; 358 359 stag_header_kernel = (struct stag_header *)(buf + AUH_SIZE); 360 361 ret = check_stag_header(buf, stag_header_kernel); 362 if (ret) 363 goto out_free_buf; 364 365 sch2_header_kernel = (struct sch2_header *)(buf + AUH_SIZE + STAG_SIZE); 366 367 ret = check_sch2_header(buf, sch2_header_kernel); 368 if (ret) 369 goto out_free_buf; 370 371 out_free_buf: 372 free(buf); 373 out: 374 return ret; 375 } 376 377 static int check_options(void) 378 { 379 int ret; 380 381 if (inspect_info.file_name) { 382 ret = get_file_stat(&inspect_info); 383 if (ret) 384 return ret; 385 386 return 0; 387 } 388 389 return 0; 390 } 391 392 int fill_sch2(struct sch2_header *header, char *kernel_ptr, char *rootfs_ptr) 393 { 394 395 header->magic = SCH2_MAGIC; 396 header->cp_type = LZMA; 397 header->version = SCH2_VER; 398 header->ram_addr = RAM_LOAD_ADDR; 399 header->image_len = kernel_info.file_size; 400 header->image_crc32 = crc32(0, (uint8_t *) kernel_ptr, kernel_info.file_size); 401 header->start_addr = RAM_ENTRY_ADDR; 402 header->rootfs_addr = 403 image_offset + STAG_SIZE + SCH2_SIZE + kernel_info.file_size; 404 header->rootfs_len = rootfs_info.file_size; 405 header->rootfs_crc32 = crc32(0, (uint8_t *) rootfs_ptr, rootfs_info.file_size); 406 header->header_crc32 = 0; 407 header->header_length = SCH2_SIZE; 408 header->cmd_line_length = 0; 409 410 header->header_crc32 = crc32(0, (uint8_t *) header, header->header_length); 411 412 return EXIT_SUCCESS; 413 } 414 415 int fill_stag(struct stag_header *header, uint32_t length) 416 { 417 header->cmark = STAG_ID; 418 header->id = STAG_ID; 419 header->magic = STAG_MAGIC; 420 header->time_stamp = jboot_timestamp(); 421 header->image_length = length + SCH2_SIZE; 422 header->image_checksum = 423 jboot_checksum(0, (uint16_t *) ((char *)header + STAG_SIZE), 424 header->image_length); 425 header->tag_checksum = 426 ~jboot_checksum(0, (uint16_t *) header, STAG_SIZE - 2); 427 428 if (image_type == FACTORY) 429 header->cmark = STAG_CMARK_FACTORY; 430 431 return EXIT_SUCCESS; 432 }; 433 434 int fill_auh(struct auh_header *header, uint32_t length) 435 { 436 memcpy(header->rom_id, rom_id, 12); 437 header->derange = 0; 438 header->image_checksum = 439 jboot_checksum(0, (uint16_t *) ((char *)header + AUH_SIZE), length); 440 header->space1 = 0; 441 header->space2 = 0; 442 header->space3 = 0; 443 header->lpvs = AUH_LVPS; 444 header->mbz = 0; 445 header->time_stamp = jboot_timestamp(); 446 header->erase_start = image_offset; 447 header->erase_length = firmware_size; 448 header->data_offset = image_offset; 449 header->data_length = length; 450 header->space4 = 0; 451 header->space5 = 0; 452 header->space6 = 0; 453 header->space7 = 0; 454 header->header_id = AUH_HDR_ID; 455 header->header_version = AUH_HDR_VER; 456 header->space8 = 0; 457 header->section_id = AUH_SEC_ID; 458 header->image_info_type = AUH_INFO_TYPE; 459 header->image_info_offset = 0; 460 header->family_member = family_member; 461 header->header_checksum = 462 ~jboot_checksum(0, (uint16_t *) header, AUH_SIZE - 2); 463 464 return EXIT_SUCCESS; 465 } 466 467 int build_fw(void) 468 { 469 char *buf; 470 char *kernel_ptr; 471 char *rootfs_ptr; 472 int ret = EXIT_FAILURE; 473 int writelen; 474 475 struct stag_header *stag_header_kernel; 476 struct sch2_header *sch2_header_kernel; 477 478 if (!kernel_info.file_name | !rootfs_info.file_name) 479 goto out; 480 481 ret = get_file_stat(&kernel_info); 482 if (ret) 483 goto out; 484 ret = get_file_stat(&rootfs_info); 485 if (ret) 486 goto out; 487 488 buf = malloc(firmware_size); 489 if (!buf) { 490 ERR("no memory for buffer\n"); 491 goto out; 492 } 493 494 if (rootfs_info.file_size + kernel_info.file_size + ALL_HEADERS_SIZE > 495 firmware_size) { 496 ERR("data is bigger than firmware_size!\n"); 497 goto out; 498 } 499 500 memset(buf, 0xff, firmware_size); 501 502 stag_header_kernel = (struct stag_header *)buf; 503 504 sch2_header_kernel = 505 (struct sch2_header *)((char *)stag_header_kernel + STAG_SIZE); 506 kernel_ptr = (char *)sch2_header_kernel + SCH2_SIZE; 507 508 ret = read_to_buf(&kernel_info, kernel_ptr); 509 if (ret) 510 goto out_free_buf; 511 512 rootfs_ptr = kernel_ptr + kernel_info.file_size; 513 514 ret = read_to_buf(&rootfs_info, rootfs_ptr); 515 if (ret) 516 goto out_free_buf; 517 518 writelen = rootfs_ptr + rootfs_info.file_size - buf; 519 520 fill_sch2(sch2_header_kernel, kernel_ptr, rootfs_ptr); 521 fill_stag(stag_header_kernel, kernel_info.file_size); 522 523 ret = write_fw(ofname, buf, writelen); 524 if (ret) 525 goto out_free_buf; 526 527 ret = EXIT_SUCCESS; 528 529 out_free_buf: 530 free(buf); 531 out: 532 return ret; 533 } 534 535 int wrap_fw(void) 536 { 537 char *buf; 538 char *image_ptr; 539 int ret = EXIT_FAILURE; 540 int writelen; 541 542 struct auh_header *auh_header_kernel; 543 544 if (!image_info.file_name) 545 goto out; 546 547 ret = get_file_stat(&image_info); 548 if (ret) 549 goto out; 550 551 buf = malloc(firmware_size); 552 if (!buf) { 553 ERR("no memory for buffer\n"); 554 goto out; 555 } 556 557 if (image_info.file_size + AUH_SIZE > 558 firmware_size) { 559 ERR("data is bigger than firmware_size!\n"); 560 goto out; 561 } 562 if (!family_member) { 563 ERR("No family_member!\n"); 564 goto out; 565 } 566 if (!(rom_id[0])) { 567 ERR("No rom_id!\n"); 568 goto out; 569 } 570 memset(buf, 0xff, firmware_size); 571 572 image_ptr = (char *)(buf + AUH_SIZE); 573 574 ret = read_to_buf(&image_info, image_ptr); 575 if (ret) 576 goto out_free_buf; 577 578 writelen = image_ptr + image_info.file_size - buf; 579 580 auh_header_kernel = (struct auh_header *)buf; 581 fill_auh(auh_header_kernel, writelen - AUH_SIZE); 582 583 ret = write_fw(ofname, buf, writelen); 584 if (ret) 585 goto out_free_buf; 586 587 ret = EXIT_SUCCESS; 588 589 out_free_buf: 590 free(buf); 591 out: 592 return ret; 593 } 594 595 int main(int argc, char *argv[]) 596 { 597 int ret = EXIT_FAILURE; 598 599 progname = basename(argv[0]); 600 image_type = SYSUPGRADE; 601 family_member = 0; 602 firmware_size = 0; 603 image_offset = JBOOT_SIZE; 604 605 while (1) { 606 int c; 607 608 c = getopt(argc, argv, "f:F:i:hk:m:o:O:r:s:"); 609 if (c == -1) 610 break; 611 612 switch (c) { 613 case 'f': 614 sscanf(optarg, "0x%hx", &family_member); 615 break; 616 case 'F': 617 image_info.file_name = optarg; 618 image_type = FACTORY; 619 break; 620 case 'i': 621 inspect_info.file_name = optarg; 622 break; 623 case 'k': 624 kernel_info.file_name = optarg; 625 break; 626 case 'm': 627 if (strlen(optarg) == 12) 628 memcpy(rom_id, optarg, 12); 629 break; 630 case 'r': 631 rootfs_info.file_name = optarg; 632 break; 633 case 'O': 634 sscanf(optarg, "0x%x", &image_offset); 635 break; 636 case 'o': 637 ofname = optarg; 638 break; 639 case 's': 640 sscanf(optarg, "0x%x", &firmware_size); 641 break; 642 default: 643 usage(EXIT_FAILURE); 644 break; 645 } 646 } 647 648 ret = check_options(); 649 if (ret) 650 goto out; 651 652 if (!inspect_info.file_name) { 653 if (image_type == FACTORY) 654 ret = wrap_fw(); 655 else 656 ret = build_fw(); 657 } 658 else 659 ret = inspect_fw(); 660 661 out: 662 return ret; 663 664 } 665
This page was automatically generated by LXR 0.3.1. • OpenWrt