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

Sources/firmware-utils/src/mkdlinkfw.c

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt