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