• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/asusuimage.c

  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