6dbaf4ae27fe104fc40d05df63954764cdbad7ef
[openwrt/staging/mkresin.git] / tools / 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 }