firmware-utils: mkdlinkfw: add kernel image offset
[openwrt/staging/dedeckeh.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 }