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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt