1/* 2 Copyright (c) 2014, Matthias Schiffer <mschiffer@universe-factory.net> 3 All rights reserved. 4 5 Redistribution and use in source and binary forms, with or without 6 modification, are permitted provided that the following conditions are met: 7 8 1. Redistributions of source code must retain the above copyright notice, 9 this list of conditions and the following disclaimer. 10 2. Redistributions in binary form must reproduce the above copyright notice, 11 this list of conditions and the following disclaimer in the documentation 12 and/or other materials provided with the distribution. 13 14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24*/ 25 26 27/* 28 tplink-safeloader 29 30 Image generation tool for the TP-LINK SafeLoader as seen on 31 TP-LINK Pharos devices (CPE210/220/510/520) 32*/ 33 34 35#include <assert.h> 36#include <errno.h> 37#include <stdbool.h> 38#include <stdio.h> 39#include <stdint.h> 40#include <stdlib.h> 41#include <string.h> 42#include <time.h> 43#include <unistd.h> 44 45#include <arpa/inet.h> 46 47#include <sys/types.h> 48#include <sys/stat.h> 49 50#include "md5.h" 51 52 53#define ALIGN(x,a) ({ typeof(a) __a = (a); (((x) + __a - 1) & ~(__a - 1)); }) 54 55 56/** An image partition table entry */ 57struct image_partition_entry { 58 const char *name; 59 size_t size; 60 uint8_t *data; 61}; 62 63/** A flash partition table entry */ 64struct flash_partition_entry { 65 const char *name; 66 uint32_t base; 67 uint32_t size; 68}; 69 70 71/** The content of the soft-version structure */ 72struct __attribute__((__packed__)) soft_version { 73 uint32_t magic; 74 uint32_t zero; 75 uint8_t pad1; 76 uint8_t version_major; 77 uint8_t version_minor; 78 uint8_t version_patch; 79 uint8_t year_hi; 80 uint8_t year_lo; 81 uint8_t month; 82 uint8_t day; 83 uint32_t rev; 84 uint8_t pad2; 85}; 86 87 88static const uint8_t jffs2_eof_mark[4] = {0xde, 0xad, 0xc0, 0xde}; 89 90 91/** 92 Salt for the MD5 hash 93 94 Fortunately, TP-LINK seems to use the same salt for most devices which use 95 the new image format. 96*/ 97static const uint8_t md5_salt[16] = { 98 0x7a, 0x2b, 0x15, 0xed, 99 0x9b, 0x98, 0x59, 0x6d, 100 0xe5, 0x04, 0xab, 0x44, 101 0xac, 0x2a, 0x9f, 0x4e, 102}; 103 104 105/** Vendor information for CPE210/220/510/520 */ 106static const char cpe510_vendor[] = "CPE510(TP-LINK|UN|N300-5):1.0\r\n"; 107 108/** Vendor information for C2600 */ 109static const char c2600_vendor[] = ""; 110 111/** Vendor information for C2600 */ 112static const char tl1043ndv4_vendor[] = ""; 113 114/** 115 The flash partition table for CPE210/220/510/520; 116 it is the same as the one used by the stock images. 117*/ 118static const struct flash_partition_entry cpe510_partitions[] = { 119 {"fs-uboot", 0x00000, 0x20000}, 120 {"partition-table", 0x20000, 0x02000}, 121 {"default-mac", 0x30000, 0x00020}, 122 {"product-info", 0x31100, 0x00100}, 123 {"signature", 0x32000, 0x00400}, 124 {"os-image", 0x40000, 0x170000}, 125 {"soft-version", 0x1b0000, 0x00100}, 126 {"support-list", 0x1b1000, 0x00400}, 127 {"file-system", 0x1c0000, 0x600000}, 128 {"user-config", 0x7c0000, 0x10000}, 129 {"default-config", 0x7d0000, 0x10000}, 130 {"log", 0x7e0000, 0x10000}, 131 {"radio", 0x7f0000, 0x10000}, 132 {NULL, 0, 0} 133}; 134 135/** 136 The flash partition table for C2600; 137 it is the same as the one used by the stock images. 138*/ 139static const struct flash_partition_entry c2600_partitions[] = { 140 {"SBL1", 0x00000, 0x20000}, 141 {"MIBIB", 0x20000, 0x20000}, 142 {"SBL2", 0x40000, 0x20000}, 143 {"SBL3", 0x60000, 0x30000}, 144 {"DDRCONFIG", 0x90000, 0x10000}, 145 {"SSD", 0xa0000, 0x10000}, 146 {"TZ", 0xb0000, 0x30000}, 147 {"RPM", 0xe0000, 0x20000}, 148 {"fs-uboot", 0x100000, 0x70000}, 149 {"uboot-env", 0x170000, 0x40000}, 150 {"radio", 0x1b0000, 0x40000}, 151 {"os-image", 0x1f0000, 0x200000}, 152 {"file-system", 0x3f0000, 0x1b00000}, 153 {"default-mac", 0x1ef0000, 0x00200}, 154 {"pin", 0x1ef0200, 0x00200}, 155 {"product-info", 0x1ef0400, 0x0fc00}, 156 {"partition-table", 0x1f00000, 0x10000}, 157 {"soft-version", 0x1f10000, 0x10000}, 158 {"support-list", 0x1f20000, 0x10000}, 159 {"profile", 0x1f30000, 0x10000}, 160 {"default-config", 0x1f40000, 0x10000}, 161 {"user-config", 0x1f50000, 0x40000}, 162 {"qos-db", 0x1f90000, 0x40000}, 163 {"usb-config", 0x1fd0000, 0x10000}, 164 {"log", 0x1fe0000, 0x20000}, 165 {NULL, 0, 0} 166}; 167 168/** 169 The flash partition table for TL1043NDv4; 170 it is the same as the one used by the stock images. 171*/ 172static const struct flash_partition_entry tl1043ndv4_partitions[] = { 173 {"fs-uboot", 0x00000, 0x20000}, 174 {"os-image", 0x20000, 0x180000}, 175 {"file-system", 0x1a0000, 0xdb0000}, 176 {"default-mac", 0xf50000, 0x00200}, 177 {"pin", 0xf50200, 0x00200}, 178 {"product-info", 0xf50400, 0x0fc00}, 179 {"soft-version", 0xf60000, 0x0b000}, 180 {"support-list", 0xf6b000, 0x04000}, 181 {"profile", 0xf70000, 0x04000}, 182 {"default-config", 0xf74000, 0x0b000}, 183 {"user-config", 0xf80000, 0x40000}, 184 {"partition-table", 0xfc0000, 0x10000}, 185 {"log", 0xfd0000, 0x20000}, 186 {"radio", 0xff0000, 0x10000}, 187 {NULL, 0, 0} 188}; 189 190/** 191 The support list for CPE210/220/510/520 192*/ 193static const char cpe510_support_list[] = 194 "SupportList:\r\n" 195 "CPE510(TP-LINK|UN|N300-5):1.0\r\n" 196 "CPE510(TP-LINK|UN|N300-5):1.1\r\n" 197 "CPE520(TP-LINK|UN|N300-5):1.0\r\n" 198 "CPE520(TP-LINK|UN|N300-5):1.1\r\n" 199 "CPE210(TP-LINK|UN|N300-2):1.0\r\n" 200 "CPE210(TP-LINK|UN|N300-2):1.1\r\n" 201 "CPE220(TP-LINK|UN|N300-2):1.0\r\n" 202 "CPE220(TP-LINK|UN|N300-2):1.1\r\n"; 203 204/** 205 The support list for C2600 206*/ 207static const char c2600_support_list[] = 208 "SupportList:\r\n" 209 "{product_name:Archer C2600,product_ver:1.0.0,special_id:00000000}\r\n"; 210 211/** 212 The support list for TL1043NDv4 213*/ 214static const char tl1043ndv4_support_list[] = 215 "SupportList:\r\n" 216 "{product_name:TL-WR1043ND,product_ver:4.0.0,special_id:45550000}\r\n"; 217 218 219#define error(_ret, _errno, _str, ...) \ 220 do { \ 221 fprintf(stderr, _str ": %s\n", ## __VA_ARGS__, \ 222 strerror(_errno)); \ 223 if (_ret) \ 224 exit(_ret); \ 225 } while (0) 226 227 228/** Stores a uint32 as big endian */ 229static inline void put32(uint8_t *buf, uint32_t val) { 230 buf[0] = val >> 24; 231 buf[1] = val >> 16; 232 buf[2] = val >> 8; 233 buf[3] = val; 234} 235 236/** Allocates a new image partition */ 237static struct image_partition_entry alloc_image_partition(const char *name, size_t len) { 238 struct image_partition_entry entry = {name, len, malloc(len)}; 239 if (!entry.data) 240 error(1, errno, "malloc"); 241 242 return entry; 243} 244 245/** Frees an image partition */ 246static void free_image_partition(struct image_partition_entry entry) { 247 free(entry.data); 248} 249 250/** Generates the partition-table partition */ 251static struct image_partition_entry make_partition_table(const struct flash_partition_entry *p) { 252 struct image_partition_entry entry = alloc_image_partition("partition-table", 0x800); 253 254 char *s = (char *)entry.data, *end = (char *)(s+entry.size); 255 256 *(s++) = 0x00; 257 *(s++) = 0x04; 258 *(s++) = 0x00; 259 *(s++) = 0x00; 260 261 size_t i; 262 for (i = 0; p[i].name; i++) { 263 size_t len = end-s; 264 size_t w = snprintf(s, len, "partition %s base 0x%05x size 0x%05x\n", p[i].name, p[i].base, p[i].size); 265 266 if (w > len-1) 267 error(1, 0, "flash partition table overflow?"); 268 269 s += w; 270 } 271 272 s++; 273 274 memset(s, 0xff, end-s); 275 276 return entry; 277} 278 279 280/** Generates a binary-coded decimal representation of an integer in the range [0, 99] */ 281static inline uint8_t bcd(uint8_t v) { 282 return 0x10 * (v/10) + v%10; 283} 284 285 286/** Generates the soft-version partition */ 287static struct image_partition_entry make_soft_version(uint32_t rev) { 288 struct image_partition_entry entry = alloc_image_partition("soft-version", sizeof(struct soft_version)); 289 struct soft_version *s = (struct soft_version *)entry.data; 290 291 time_t t; 292 293 if (time(&t) == (time_t)(-1)) 294 error(1, errno, "time"); 295 296 struct tm *tm = localtime(&t); 297 298 s->magic = htonl(0x0000000c); 299 s->zero = 0; 300 s->pad1 = 0xff; 301 302 s->version_major = 0; 303 s->version_minor = 0; 304 s->version_patch = 0; 305 306 s->year_hi = bcd((1900+tm->tm_year)/100); 307 s->year_lo = bcd(tm->tm_year%100); 308 s->month = bcd(tm->tm_mon+1); 309 s->day = bcd(tm->tm_mday); 310 s->rev = htonl(rev); 311 312 s->pad2 = 0xff; 313 314 return entry; 315} 316 317/** Generates the support-list partition */ 318static struct image_partition_entry make_support_list(const char *support_list, bool trailzero) { 319 size_t len = strlen(support_list); 320 struct image_partition_entry entry = alloc_image_partition("support-list", len + 9); 321 322 put32(entry.data, len); 323 memset(entry.data+4, 0, 4); 324 memcpy(entry.data+8, support_list, len); 325 entry.data[len+8] = trailzero ? '\x00' : '\xff'; 326 327 return entry; 328} 329 330/** Creates a new image partition with an arbitrary name from a file */ 331static struct image_partition_entry read_file(const char *part_name, const char *filename, bool add_jffs2_eof) { 332 struct stat statbuf; 333 334 if (stat(filename, &statbuf) < 0) 335 error(1, errno, "unable to stat file `%s'", filename); 336 337 size_t len = statbuf.st_size; 338 339 if (add_jffs2_eof) 340 len = ALIGN(len, 0x10000) + sizeof(jffs2_eof_mark); 341 342 struct image_partition_entry entry = alloc_image_partition(part_name, len); 343 344 FILE *file = fopen(filename, "rb"); 345 if (!file) 346 error(1, errno, "unable to open file `%s'", filename); 347 348 if (fread(entry.data, statbuf.st_size, 1, file) != 1) 349 error(1, errno, "unable to read file `%s'", filename); 350 351 if (add_jffs2_eof) { 352 uint8_t *eof = entry.data + statbuf.st_size, *end = entry.data+entry.size; 353 354 memset(eof, 0xff, end - eof - sizeof(jffs2_eof_mark)); 355 memcpy(end - sizeof(jffs2_eof_mark), jffs2_eof_mark, sizeof(jffs2_eof_mark)); 356 } 357 358 fclose(file); 359 360 return entry; 361} 362 363 364/** 365 Copies a list of image partitions into an image buffer and generates the image partition table while doing so 366 367 Example image partition table: 368 369 fwup-ptn partition-table base 0x00800 size 0x00800 370 fwup-ptn os-image base 0x01000 size 0x113b45 371 fwup-ptn file-system base 0x114b45 size 0x1d0004 372 fwup-ptn support-list base 0x2e4b49 size 0x000d1 373 374 Each line of the partition table is terminated with the bytes 09 0d 0a ("\t\r\n"), 375 the end of the partition table is marked with a zero byte. 376 377 The firmware image must contain at least the partition-table and support-list partitions 378 to be accepted. There aren't any alignment constraints for the image partitions. 379 380 The partition-table partition contains the actual flash layout; partitions 381 from the image partition table are mapped to the corresponding flash partitions during 382 the firmware upgrade. The support-list partition contains a list of devices supported by 383 the firmware image. 384 385 The base offsets in the firmware partition table are relative to the end 386 of the vendor information block, so the partition-table partition will 387 actually start at offset 0x1814 of the image. 388 389 I think partition-table must be the first partition in the firmware image. 390*/ 391static void put_partitions(uint8_t *buffer, const struct image_partition_entry *parts) { 392 size_t i; 393 char *image_pt = (char *)buffer, *end = image_pt + 0x800; 394 395 size_t base = 0x800; 396 for (i = 0; parts[i].name; i++) { 397 memcpy(buffer + base, parts[i].data, parts[i].size); 398 399 size_t len = end-image_pt; 400 size_t w = snprintf(image_pt, len, "fwup-ptn %s base 0x%05x size 0x%05x\t\r\n", parts[i].name, (unsigned)base, (unsigned)parts[i].size); 401 402 if (w > len-1) 403 error(1, 0, "image partition table overflow?"); 404 405 image_pt += w; 406 407 base += parts[i].size; 408 } 409 410 image_pt++; 411 412 memset(image_pt, 0xff, end-image_pt); 413} 414 415/** Generates and writes the image MD5 checksum */ 416static void put_md5(uint8_t *md5, uint8_t *buffer, unsigned int len) { 417 MD5_CTX ctx; 418 419 MD5_Init(&ctx); 420 MD5_Update(&ctx, md5_salt, (unsigned int)sizeof(md5_salt)); 421 MD5_Update(&ctx, buffer, len); 422 MD5_Final(md5, &ctx); 423} 424 425 426/** 427 Generates the firmware image in factory format 428 429 Image format: 430 431 Bytes (hex) Usage 432 ----------- ----- 433 0000-0003 Image size (4 bytes, big endian) 434 0004-0013 MD5 hash (hash of a 16 byte salt and the image data starting with byte 0x14) 435 0014-0017 Vendor information length (without padding) (4 bytes, big endian) 436 0018-1013 Vendor information (4092 bytes, padded with 0xff; there seem to be older 437 (VxWorks-based) TP-LINK devices which use a smaller vendor information block) 438 1014-1813 Image partition table (2048 bytes, padded with 0xff) 439 1814-xxxx Firmware partitions 440*/ 441static void * generate_factory_image(const char *vendor, const struct image_partition_entry *parts, size_t *len) { 442 *len = 0x1814; 443 444 size_t i; 445 for (i = 0; parts[i].name; i++) 446 *len += parts[i].size; 447 448 uint8_t *image = malloc(*len); 449 if (!image) 450 error(1, errno, "malloc"); 451 452 put32(image, *len); 453 454 size_t vendor_len = strlen(vendor); 455 put32(image+0x14, vendor_len); 456 memcpy(image+0x18, vendor, vendor_len); 457 memset(image+0x18+vendor_len, 0xff, 4092-vendor_len); 458 459 put_partitions(image + 0x1014, parts); 460 put_md5(image+0x04, image+0x14, *len-0x14); 461 462 return image; 463} 464 465/** 466 Generates the firmware image in sysupgrade format 467 468 This makes some assumptions about the provided flash and image partition tables and 469 should be generalized when TP-LINK starts building its safeloader into hardware with 470 different flash layouts. 471*/ 472static void * generate_sysupgrade_image(const struct flash_partition_entry *flash_parts, const struct image_partition_entry *image_parts, size_t *len) { 473 const struct flash_partition_entry *flash_os_image = &flash_parts[5]; 474 const struct flash_partition_entry *flash_soft_version = &flash_parts[6]; 475 const struct flash_partition_entry *flash_support_list = &flash_parts[7]; 476 const struct flash_partition_entry *flash_file_system = &flash_parts[8]; 477 478 const struct image_partition_entry *image_os_image = &image_parts[3]; 479 const struct image_partition_entry *image_soft_version = &image_parts[1]; 480 const struct image_partition_entry *image_support_list = &image_parts[2]; 481 const struct image_partition_entry *image_file_system = &image_parts[4]; 482 483 assert(strcmp(flash_os_image->name, "os-image") == 0); 484 assert(strcmp(flash_soft_version->name, "soft-version") == 0); 485 assert(strcmp(flash_support_list->name, "support-list") == 0); 486 assert(strcmp(flash_file_system->name, "file-system") == 0); 487 488 assert(strcmp(image_os_image->name, "os-image") == 0); 489 assert(strcmp(image_soft_version->name, "soft-version") == 0); 490 assert(strcmp(image_support_list->name, "support-list") == 0); 491 assert(strcmp(image_file_system->name, "file-system") == 0); 492 493 if (image_os_image->size > flash_os_image->size) 494 error(1, 0, "kernel image too big (more than %u bytes)", (unsigned)flash_os_image->size); 495 if (image_file_system->size > flash_file_system->size) 496 error(1, 0, "rootfs image too big (more than %u bytes)", (unsigned)flash_file_system->size); 497 498 *len = flash_file_system->base - flash_os_image->base + image_file_system->size; 499 500 uint8_t *image = malloc(*len); 501 if (!image) 502 error(1, errno, "malloc"); 503 504 memset(image, 0xff, *len); 505 506 memcpy(image, image_os_image->data, image_os_image->size); 507 memcpy(image + flash_soft_version->base - flash_os_image->base, image_soft_version->data, image_soft_version->size); 508 memcpy(image + flash_support_list->base - flash_os_image->base, image_support_list->data, image_support_list->size); 509 memcpy(image + flash_file_system->base - flash_os_image->base, image_file_system->data, image_file_system->size); 510 511 return image; 512} 513 514static void * generate_sysupgrade_image_c2600(const struct flash_partition_entry *flash_parts, const struct image_partition_entry *image_parts, size_t *len) { 515 const struct flash_partition_entry *flash_os_image = &flash_parts[11]; 516 const struct flash_partition_entry *flash_file_system = &flash_parts[12]; 517 518 const struct image_partition_entry *image_os_image = &image_parts[3]; 519 const struct image_partition_entry *image_file_system = &image_parts[4]; 520 521 assert(strcmp(flash_os_image->name, "os-image") == 0); 522 assert(strcmp(flash_file_system->name, "file-system") == 0); 523 524 assert(strcmp(image_os_image->name, "os-image") == 0); 525 assert(strcmp(image_file_system->name, "file-system") == 0); 526 527 if (image_os_image->size > flash_os_image->size) 528 error(1, 0, "kernel image too big (more than %u bytes)", (unsigned)flash_os_image->size); 529 if (image_file_system->size > flash_file_system->size) 530 error(1, 0, "rootfs image too big (more than %u bytes)", (unsigned)flash_file_system->size); 531 532 *len = flash_file_system->base - flash_os_image->base + image_file_system->size; 533 534 uint8_t *image = malloc(*len); 535 if (!image) 536 error(1, errno, "malloc"); 537 538 memset(image, 0xff, *len); 539 540 memcpy(image, image_os_image->data, image_os_image->size); 541 memcpy(image + flash_file_system->base - flash_os_image->base, image_file_system->data, image_file_system->size); 542 543 return image; 544} 545 546static void * generate_sysupgrade_image_tl1043ndv4(const struct flash_partition_entry *flash_parts, const struct image_partition_entry *image_parts, size_t *len) { 547 const struct flash_partition_entry *flash_os_image = &flash_parts[1]; 548 const struct flash_partition_entry *flash_file_system = &flash_parts[2]; 549 550 const struct image_partition_entry *image_os_image = &image_parts[3]; 551 const struct image_partition_entry *image_file_system = &image_parts[4]; 552 553 assert(strcmp(flash_os_image->name, "os-image") == 0); 554 assert(strcmp(flash_file_system->name, "file-system") == 0); 555 556 assert(strcmp(image_os_image->name, "os-image") == 0); 557 assert(strcmp(image_file_system->name, "file-system") == 0); 558 559 if (image_os_image->size > flash_os_image->size) 560 error(1, 0, "kernel image too big (more than %u bytes)", (unsigned)flash_os_image->size); 561 if (image_file_system->size > flash_file_system->size) 562 error(1, 0, "rootfs image too big (more than %u bytes)", (unsigned)flash_file_system->size); 563 564 *len = flash_file_system->base - flash_os_image->base + image_file_system->size; 565 566 uint8_t *image = malloc(*len); 567 if (!image) 568 error(1, errno, "malloc"); 569 570 memset(image, 0xff, *len); 571 572 memcpy(image, image_os_image->data, image_os_image->size); 573 memcpy(image + flash_file_system->base - flash_os_image->base, image_file_system->data, image_file_system->size); 574 575 return image; 576} 577 578/** Generates an image for CPE210/220/510/520 and writes it to a file */ 579static void do_cpe510(const char *output, const char *kernel_image, const char *rootfs_image, uint32_t rev, bool add_jffs2_eof, bool sysupgrade) { 580 struct image_partition_entry parts[6] = {}; 581 582 parts[0] = make_partition_table(cpe510_partitions); 583 parts[1] = make_soft_version(rev); 584 parts[2] = make_support_list(cpe510_support_list,false); 585 parts[3] = read_file("os-image", kernel_image, false); 586 parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof); 587 588 size_t len; 589 void *image; 590 if (sysupgrade) 591 image = generate_sysupgrade_image(cpe510_partitions, parts, &len); 592 else 593 image = generate_factory_image(cpe510_vendor, parts, &len); 594 595 FILE *file = fopen(output, "wb"); 596 if (!file) 597 error(1, errno, "unable to open output file"); 598 599 if (fwrite(image, len, 1, file) != 1) 600 error(1, 0, "unable to write output file"); 601 602 fclose(file); 603 604 free(image); 605 606 size_t i; 607 for (i = 0; parts[i].name; i++) 608 free_image_partition(parts[i]); 609} 610 611/** Generates an image for C2600 and writes it to a file */ 612static void do_c2600(const char *output, const char *kernel_image, const char *rootfs_image, uint32_t rev, bool add_jffs2_eof, bool sysupgrade) { 613 struct image_partition_entry parts[6] = {}; 614 615 parts[0] = make_partition_table(c2600_partitions); 616 parts[1] = make_soft_version(rev); 617 parts[2] = make_support_list(c2600_support_list,true); 618 parts[3] = read_file("os-image", kernel_image, false); 619 parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof); 620 621 size_t len; 622 void *image; 623 if (sysupgrade) 624 image = generate_sysupgrade_image_c2600(c2600_partitions, parts, &len); 625 else 626 image = generate_factory_image(c2600_vendor, parts, &len); 627 628 FILE *file = fopen(output, "wb"); 629 if (!file) 630 error(1, errno, "unable to open output file"); 631 632 if (fwrite(image, len, 1, file) != 1) 633 error(1, 0, "unable to write output file"); 634 635 fclose(file); 636 637 free(image); 638 639 size_t i; 640 for (i = 0; parts[i].name; i++) 641 free_image_partition(parts[i]); 642} 643 644/** Generates an image for TL1043NDv4 and writes it to a file */ 645static void do_tl1043ndv4(const char *output, const char *kernel_image, const char *rootfs_image, uint32_t rev, bool add_jffs2_eof, bool sysupgrade) { 646 struct image_partition_entry parts[6] = {}; 647 648 parts[0] = make_partition_table(tl1043ndv4_partitions); 649 parts[1] = make_soft_version(rev); 650 parts[2] = make_support_list(tl1043ndv4_support_list,true); 651 parts[3] = read_file("os-image", kernel_image, false); 652 parts[4] = read_file("file-system", rootfs_image, add_jffs2_eof); 653 654 size_t len; 655 void *image; 656 if (sysupgrade) 657 image = generate_sysupgrade_image_tl1043ndv4(tl1043ndv4_partitions, parts, &len); 658 else 659 image = generate_factory_image(tl1043ndv4_vendor, parts, &len); 660 661 FILE *file = fopen(output, "wb"); 662 if (!file) 663 error(1, errno, "unable to open output file"); 664 665 if (fwrite(image, len, 1, file) != 1) 666 error(1, 0, "unable to write output file"); 667 668 fclose(file); 669 670 free(image); 671 672 size_t i; 673 for (i = 0; parts[i].name; i++) 674 free_image_partition(parts[i]); 675} 676 677 678/** Usage output */ 679static void usage(const char *argv0) { 680 fprintf(stderr, 681 "Usage: %s [OPTIONS...]\n" 682 "\n" 683 "Options:\n" 684 " -B <board> create image for the board specified with <board>\n" 685 " -k <file> read kernel image from the file <file>\n" 686 " -r <file> read rootfs image from the file <file>\n" 687 " -o <file> write output to the file <file>\n" 688 " -V <rev> sets the revision number to <rev>\n" 689 " -j add jffs2 end-of-filesystem markers\n" 690 " -S create sysupgrade instead of factory image\n" 691 " -h show this help\n", 692 argv0 693 ); 694}; 695 696 697int main(int argc, char *argv[]) { 698 const char *board = NULL, *kernel_image = NULL, *rootfs_image = NULL, *output = NULL; 699 bool add_jffs2_eof = false, sysupgrade = false; 700 unsigned rev = 0; 701 702 while (true) { 703 int c; 704 705 c = getopt(argc, argv, "B:k:r:o:V:jSh"); 706 if (c == -1) 707 break; 708 709 switch (c) { 710 case 'B': 711 board = optarg; 712 break; 713 714 case 'k': 715 kernel_image = optarg; 716 break; 717 718 case 'r': 719 rootfs_image = optarg; 720 break; 721 722 case 'o': 723 output = optarg; 724 break; 725 726 case 'V': 727 sscanf(optarg, "r%u", &rev); 728 break; 729 730 case 'j': 731 add_jffs2_eof = true; 732 break; 733 734 case 'S': 735 sysupgrade = true; 736 break; 737 738 case 'h': 739 usage(argv[0]); 740 return 0; 741 742 default: 743 usage(argv[0]); 744 return 1; 745 } 746 } 747 748 if (!board) 749 error(1, 0, "no board has been specified"); 750 if (!kernel_image) 751 error(1, 0, "no kernel image has been specified"); 752 if (!rootfs_image) 753 error(1, 0, "no rootfs image has been specified"); 754 if (!output) 755 error(1, 0, "no output filename has been specified"); 756 757 if (strcmp(board, "CPE510") == 0) 758 do_cpe510(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade); 759 else if (strcmp(board, "C2600") == 0) 760 do_c2600(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade); 761 else if (strcmp(board, "TLWR1043NDV4") == 0) 762 do_tl1043ndv4(output, kernel_image, rootfs_image, rev, add_jffs2_eof, sysupgrade); 763 else 764 error(1, 0, "unsupported board %s", board); 765 766 return 0; 767} 768